From d071daf34edbaa24aadbb4c97be118ba3af7697f Mon Sep 17 00:00:00 2001 From: Cherisher Date: Thu, 22 Aug 2019 09:02:09 +0800 Subject: [PATCH] add support for nginx --- binding/ngx-ip2region/README.md | 4 + binding/ngx-ip2region/config | 44 ++++ binding/ngx-ip2region/ngx_ip2region.h | 23 ++ binding/ngx-ip2region/ngx_ip2region_module.c | 260 +++++++++++++++++++ 4 files changed, 331 insertions(+) create mode 100644 binding/ngx-ip2region/README.md create mode 100644 binding/ngx-ip2region/config create mode 100644 binding/ngx-ip2region/ngx_ip2region.h create mode 100644 binding/ngx-ip2region/ngx_ip2region_module.c diff --git a/binding/ngx-ip2region/README.md b/binding/ngx-ip2region/README.md new file mode 100644 index 0000000..ffd4d59 --- /dev/null +++ b/binding/ngx-ip2region/README.md @@ -0,0 +1,4 @@ +#说明 + +- 本模块依赖[ip2region](https://github.com/lionsoul2014/ip2region/tree/master/binding/c)项目,需要手动下载ip2region.c 和 ip2region.h文件后进行编译 + diff --git a/binding/ngx-ip2region/config b/binding/ngx-ip2region/config new file mode 100644 index 0000000..0546d22 --- /dev/null +++ b/binding/ngx-ip2region/config @@ -0,0 +1,44 @@ +ngx_addon_name="ngx_ip2region_module" + +IP2REGION_CORE_MODULES=" \ + ngx_ip2region_module \ + " + +IP2REGION_DEPS=" \ + $ngx_addon_dir/ip2region.h \ + $ngx_addon_dir/ngx_ip2region.h \ + " + +IP2REGION_CORE_SRCS=" \ + $ngx_addon_dir/ip2region.c \ + $ngx_addon_dir/ngx_ip2region_module.c \ + " + + + +if [ -f auto/module ] ; then + ngx_module_incs=$ngx_addon_dir + ngx_module_deps=$IP2REGION_DEPS + + if [ $ngx_module_link = DYNAMIC ] ; then + ngx_module_name="$IP2REGION_CORE_MODULES" + ngx_module_srcs="$IP2REGION_CORE_SRCS" + + . auto/module + + else + ngx_module_type=CORE + ngx_module_name=$IP2REGION_CORE_MODULES + ngx_module_srcs=$IP2REGION_CORE_SRCS + + . auto/module + fi + +else + CORE_MODULES="$CORE_MODULES $IP2REGION_CORE_MODULES" + + NGX_ADDON_DEPS="$NGX_ADDON_DEPS $IP2REGION_DEPS" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $IP2REGION_CORE_SRCS" + + CFLAGS="$CFLAGS -I$ngx_addon_dir " +fi diff --git a/binding/ngx-ip2region/ngx_ip2region.h b/binding/ngx-ip2region/ngx_ip2region.h new file mode 100644 index 0000000..f7728c7 --- /dev/null +++ b/binding/ngx-ip2region/ngx_ip2region.h @@ -0,0 +1,23 @@ +#ifndef __NGX_IP2REGION_H__ +#define __NGX_IP2REGION_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../binding/c/ip2region.h" + +typedef struct ngx_ip2region_conf_s { + ngx_str_t db_file; + ngx_uint_t algo; +} ngx_ip2region_conf_t; + +typedef uint_t (*search_func_ptr)(ip2region_t, uint_t, datablock_t); + +extern ngx_int_t ngx_ip2region_search(ngx_str_t *addr_text, ngx_str_t *isp, ngx_str_t *city); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/binding/ngx-ip2region/ngx_ip2region_module.c b/binding/ngx-ip2region/ngx_ip2region_module.c new file mode 100644 index 0000000..97365c3 --- /dev/null +++ b/binding/ngx-ip2region/ngx_ip2region_module.c @@ -0,0 +1,260 @@ +#include +#include + +#include "ngx_ip2region.h" + + +static void *ngx_ip2region_create_conf(ngx_cycle_t *cycle); +static char *ngx_ip2region_init_conf(ngx_cycle_t *cycle, void *conf); + +static ngx_int_t ngx_ip2region_init_process(ngx_cycle_t *cycle); +static void ngx_ip2region_exit_process(ngx_cycle_t *cycle); + +static ip2region_entry g_ip2region_entry; + + +search_func_ptr ip2region_search_func; + + +#define NGX_IP2REGION_MEMORY 0 +#define NGX_IP2REGION_BINARY 1 +#define NGX_IP2REGION_BTREE 2 + +static ngx_conf_enum_t ngx_ip2region_search_algo[] = { + { ngx_string("memory"), NGX_IP2REGION_MEMORY }, + { ngx_string("binary"), NGX_IP2REGION_BINARY }, + { ngx_string("btree"), NGX_IP2REGION_BTREE}, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_ip2region_commands[] = { + + { + ngx_string("ip2region_db_file"), + NGX_MAIN_CONF | NGX_DIRECT_CONF | NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + 0, + offsetof(ngx_ip2region_conf_t, db_file), + NULL + }, + + { + ngx_string("ip2region_algo"), + NGX_MAIN_CONF | NGX_DIRECT_CONF | NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + 0, + offsetof(ngx_ip2region_conf_t, algo), + &ngx_ip2region_search_algo + }, + + ngx_null_command +}; + + +static ngx_core_module_t ngx_ip2region_module_ctx = { + ngx_string("ip2region"), + ngx_ip2region_create_conf, + ngx_ip2region_init_conf, +}; + + +ngx_module_t ngx_ip2region_module = { + NGX_MODULE_V1, + &ngx_ip2region_module_ctx, /* module context */ + ngx_ip2region_commands, /* module directives */ + NGX_CORE_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + ngx_ip2region_init_process, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + ngx_ip2region_exit_process, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + +static void * +ngx_ip2region_create_conf(ngx_cycle_t *cycle) +{ + ngx_ip2region_conf_t *ip2region_conf; + ip2region_conf = ngx_pcalloc(cycle->pool, sizeof(ngx_ip2region_conf_t)); + + if(ip2region_conf == NULL) { + return NULL; + } + + ip2region_conf->algo = NGX_CONF_UNSET_UINT; + return ip2region_conf; +} + +static char * +ngx_ip2region_init_conf(ngx_cycle_t *cycle, void *conf) +{ + ngx_ip2region_conf_t *ip2region_conf = (ngx_ip2region_conf_t *)conf; + + if(ip2region_conf->db_file.len == 0) { + //ngx_str_set(&ip2region_conf->db_file, "conf/ip2region.db"); + return NGX_CONF_OK; + } + + if(ngx_conf_full_name(cycle, &ip2region_conf->db_file, 0) != NGX_OK) { + return NGX_CONF_ERROR; + } + + ngx_log_debug1(NGX_LOG_INFO, ngx_cycle->log, 0, "%V", &ip2region_conf->db_file); + + if(ip2region_conf->algo == NGX_CONF_UNSET_UINT) { + ip2region_conf->algo = NGX_IP2REGION_MEMORY; + } + + return NGX_CONF_OK; +} + +static ngx_int_t +ngx_ip2region_init_process(ngx_cycle_t *cycle) +{ + ngx_ip2region_conf_t *conf = (ngx_ip2region_conf_t *)ngx_get_conf(ngx_cycle->conf_ctx, ngx_ip2region_module); + + if(conf->db_file.len == 0) { + ngx_log_debug0(NGX_LOG_INFO, ngx_cycle->log, 0, "ip2region not init"); + return NGX_OK; + } + + if(!ip2region_create(&g_ip2region_entry, (char *)conf->db_file.data)) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "ip2region create failed: %V", &conf->db_file); + return NGX_ERROR; + } + + switch(conf->algo) { + default: + case NGX_IP2REGION_MEMORY: + ip2region_search_func = ip2region_memory_search; + break; + + case NGX_IP2REGION_BINARY: + ip2region_search_func = ip2region_binary_search; + break; + + case NGX_IP2REGION_BTREE: + ip2region_search_func = ip2region_btree_search; + break; + } + + ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, "ip2region create succcess: algo=%ui", conf->algo); + return NGX_OK; +} + +static void +ngx_ip2region_exit_process(ngx_cycle_t *cycle) +{ + ip2region_destroy(&g_ip2region_entry); + ngx_log_debug0(NGX_LOG_INFO, ngx_cycle->log, 0, "ip2region destroy"); +} + +static ngx_inline u_char * +ngx_strrchr(u_char *first, u_char *p, u_char c) +{ + while(p >= first) { + if(*p == c) { + return p; + } + + p--; + } + + return NULL; +} + +static ngx_inline uint32_t +ngx_inet_aton(u_char *data, ngx_uint_t len) +{ + long long result = 0; + long long temp = 0; + u_char *last = data + len; + int point = 0; + + while(data <= last) { + if(*data == '.' || data == last) { + if(temp > 255) { + return NGX_ERROR; + } + + result = (result << 8) + temp; + temp = 0; + ++point; + + if(point == 4) { + break; + } + + } else if(*data <= '9' && *data >= '0') { + temp = temp * 10 + (*data - '0'); + + } else { + return NGX_ERROR; + } + + ++data; + } + + if(point != 4) { + return NGX_ERROR; + } + + return result; +} + +ngx_int_t +ngx_ip2region_search(ngx_str_t *addr_text, ngx_str_t *isp, ngx_str_t *city) +{ + if(g_ip2region_entry.dbHandler == NULL) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "search error ip %V, ip2region doesn't create", addr_text); + return NGX_ERROR; + } + + uint32_t addr_binary = ngx_inet_aton(addr_text->data, addr_text->len); + + if(addr_binary == (uint32_t)NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "search error ip %V: bad ip address", addr_text); + return NGX_ERROR; + } + + datablock_entry datablock; + ngx_memzero(&datablock, sizeof(datablock)); + uint_t rc = ip2region_search_func(&g_ip2region_entry, (uint_t)addr_binary, &datablock); + + if(!rc) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "%V search failed", addr_text); + return NGX_ERROR; + } + + ngx_log_debug2(NGX_LOG_INFO, ngx_cycle->log, 0, "%V: %s", addr_text, datablock.region); + //城市Id 国家|区域|省份|城市|ISP + u_char *end = (u_char *)(datablock.region + ngx_strlen(datablock.region)); + u_char *pos = ngx_strrchr((u_char *)datablock.region, end, '|'); + + if(!pos) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "search isp failed"); + return NGX_ERROR; + } + + u_char isp_buffer[64] = {0}; + ngx_snprintf(isp_buffer, sizeof(isp_buffer), "%*s%Z", end - pos, pos + 1); + ngx_log_debug3(NGX_LOG_INFO, ngx_cycle->log, 0, "%V: %s [%s]", addr_text, datablock.region, (char *)isp_buffer); + + if(city) { + end = pos - 1; + u_char *pos_city = ngx_strrchr((u_char *)datablock.region, end, '|'); + + if(!pos_city) { + ngx_log_debug0(NGX_LOG_ERR, ngx_cycle->log, 0, "search city failed"); + return NGX_ERROR; + } + + u_char city_buffer[64] = {0}; + ngx_snprintf(city_buffer, sizeof(city_buffer), "%*s%Z", end - pos_city, pos_city + 1); + } + + return NGX_OK; +}