├── t ├── ipiptest.ipdb └── ipdb.t ├── ngx_stream_ipdb_lua.h ├── ngx_stream_ipdb_module.h ├── .gitignore ├── .travis.yml ├── LICENSE ├── config ├── ipdb ├── ipdb.h └── ipdb.c ├── ngx_stream_ipdb_lua.c ├── README.md └── ngx_stream_ipdb_module.c /t/ipiptest.ipdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vislee/ngx_stream_ipdb_module/HEAD/t/ipiptest.ipdb -------------------------------------------------------------------------------- /ngx_stream_ipdb_lua.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) vislee 3 | */ 4 | 5 | #ifndef _NGX_STREAM_IPDB_LUA_H 6 | #define _NGX_STREAM_IPDB_LUA_H 7 | 8 | #include 9 | #include 10 | 11 | ngx_int_t ngx_stream_ipdb_lua_preload(ngx_conf_t *cf); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /ngx_stream_ipdb_module.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) vislee 3 | */ 4 | 5 | #ifndef _NGX_STREAM_IPDB_MODULE 6 | #define _NGX_STREAM_IPDB_MODULE 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "ipdb/ipdb.h" 13 | 14 | 15 | typedef struct { 16 | ipdb_reader *ipdb; 17 | } ngx_stream_ipdb_main_conf_t; 18 | 19 | 20 | typedef struct { 21 | ngx_str_t lang; 22 | } ngx_stream_ipdb_srv_conf_t; 23 | 24 | 25 | ngx_module_t ngx_stream_ipdb_module; 26 | 27 | ngx_int_t ngx_stream_ipdb_item_by_addr(ipdb_reader *reader, ngx_addr_t *addr, 28 | const char *lang, char *body); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | os: linux 4 | 5 | compiler: 6 | - gcc 7 | 8 | addons: 9 | apt: 10 | packages: 11 | - cpanminus 12 | - lcov 13 | - libjson-c-dev 14 | 15 | install: 16 | - gem install coveralls-lcov 17 | - git clone https://github.com/nginx/nginx.git ../nginx 18 | - git clone https://github.com/nginx/nginx-tests.git ../nginx-tests 19 | - rm -f ../nginx-tests/*.t 20 | - cp ./t/* ../nginx-tests/ 21 | 22 | before_script: 23 | - lcov --directory ../nginx --zerocounters 24 | 25 | script: 26 | - ls -ltra 27 | - cd ../nginx 28 | - ls -ltra 29 | - ./auto/configure --prefix=/tmp/nginx --without-http --with-stream --with-stream_realip_module --add-module=../ngx_stream_ipdb_module 30 | --with-cc-opt="-Wno-unused-result -fprofile-arcs -ftest-coverage" --with-ld-opt="-lgcov" 31 | - make -j 32 | - make install 33 | - cd ../nginx-tests 34 | - ls -ltra 35 | - TEST_NGINX_BINARY=/tmp/nginx/sbin/nginx prove . 36 | - cd ../nginx 37 | - sudo lcov --compat-libtool --directory ./objs/addon/ngx_stream_ipdb_module/ --capture 38 | --output-file ./coverage.info --base-directory . 39 | - ls -ltra 40 | 41 | after_success: 42 | - coveralls-lcov ./coverage.info 43 | - genhtml -s -o /tmp/ipdb_html coverage.info 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, wenqiang li 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_stream_ipdb_module 2 | 3 | _STREAM_IPDB_SRCS="\ 4 | $ngx_addon_dir/ngx_stream_ipdb_module.c \ 5 | $ngx_addon_dir/ipdb/ipdb.c \ 6 | " 7 | _STREAM_IPDB_DRPS="\ 8 | $ngx_addon_dir/ngx_stream_ipdb_module.h \ 9 | " 10 | 11 | ipdb_lua() { 12 | echo " + ipdb module support lua" 13 | have=NGX_STREAM_IPDB_LUA . auto/have 14 | _STREAM_IPDB_SRCS="$_STREAM_IPDB_SRCS $ngx_addon_dir/ngx_stream_ipdb_lua.c" 15 | _STREAM_IPDB_DRPS="$_STREAM_IPDB_DRPS $ngx_addon_dir/ngx_stream_ipdb_lua.h" 16 | } 17 | 18 | echo $NGX_ADDON_DEPS | grep "ngx_stream_lua_api" > /dev/null 19 | if [ $? -eq 0 ]; then 20 | ipdb_lua 21 | fi 22 | 23 | 24 | _STREAM_JSON_LIB="-lm -ljson-c" 25 | 26 | ngx_feature="json-c library" 27 | ngx_feature_name="NGX_JSON_C" 28 | ngx_feature_run=no 29 | ngx_feature_incs="#include " 30 | ngx_feature_path= 31 | ngx_feature_libs="$_STREAM_JSON_LIB" 32 | ngx_feature_test="json_c_version_num()" 33 | . auto/feature 34 | 35 | if [ $ngx_found = yes ]; then 36 | 37 | if test -n "$ngx_module_link"; then 38 | 39 | ngx_module_type=STREAM 40 | ngx_module_name=$ngx_addon_name 41 | ngx_module_srcs="$_STREAM_IPDB_SRCS" 42 | ngx_module_libs="$_STREAM_JSON_LIB" 43 | ngx_module_deps="$_STREAM_IPDB_DRPS" 44 | 45 | . auto/module 46 | 47 | else 48 | 49 | STREAM_MODULES="$STREAM_MODULES $ngx_addon_name" 50 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $_STREAM_IPDB_SRCS" 51 | CORE_LIBS="$CORE_LIBS $_STREAM_JSON_LIB" 52 | HTTP_INCS="$HTTP_INCS $ngx_addon_dir" 53 | NGX_ADDON_DEPS="$NGX_ADDON_DEPS $_STREAM_IPDB_DRPS" 54 | fi 55 | 56 | else 57 | echo "warning: $ngx_addon_name invalid. please yum install json-c" 58 | fi 59 | -------------------------------------------------------------------------------- /ipdb/ipdb.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by root on 11/14/18. 3 | // 4 | 5 | #ifndef IPDB_C_IPDB_H 6 | #define IPDB_C_IPDB_H 7 | 8 | #define IPv4 0x01 9 | #define IPv6 0x02 10 | 11 | #define ErrNoErr 0 //No error. 12 | #define ErrFileSize 1 //"IP Database file size error." 13 | #define ErrMetaData 2 //"IP Database metadata error." 14 | //#define ErrReadFull 3 //"IP Database ReadFull error." 15 | 16 | #define ErrDatabaseError 4 //"database error" 17 | 18 | #define ErrIPFormat 5 //"Query IP Format error." 19 | 20 | #define ErrNoSupportLanguage 6 //"language not support" 21 | #define ErrNoSupportIPv4 7 //"IPv4 not support" 22 | #define ErrNoSupportIPv6 8 //"IPv6 not support" 23 | 24 | #define ErrDataNotExists 9 //"data is not exists" 25 | 26 | typedef struct ipdb_meta_data_language { 27 | char name[8]; 28 | int offset; 29 | } ipdb_meta_data_language; 30 | 31 | typedef struct ipdb_meta_data { 32 | int node_count; 33 | int total_size; 34 | short ip_version; 35 | long build_time; 36 | ipdb_meta_data_language *language; 37 | int language_length; 38 | char **fields; 39 | int fields_length; 40 | } ipdb_meta_data; 41 | 42 | typedef struct ipdb_reader { 43 | ipdb_meta_data *meta; 44 | int v4offset; 45 | int file_size; 46 | int data_size; 47 | unsigned char *data; 48 | } ipdb_reader; 49 | 50 | int ipdb_reader_new(const char *file, ipdb_reader **reader); 51 | 52 | void ipdb_reader_free(ipdb_reader **reader); 53 | 54 | int ipdb_reader_is_ipv4_support(ipdb_reader *reader); 55 | 56 | int ipdb_reader_is_ipv6_support(ipdb_reader *reader); 57 | 58 | int ipdb_reader_find(ipdb_reader *reader, const char *addr, const char *language, char *body); 59 | 60 | int ipdb_search(ipdb_reader *reader, const u_char *ip, int bit_count, int *node); 61 | int ipdb_resolve(ipdb_reader *reader, int node, const char **bytes); 62 | #endif //IPDB_C_IPDB_H 63 | -------------------------------------------------------------------------------- /t/ipdb.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # (C) vislee 4 | 5 | # Tests for stream ipdb module. 6 | 7 | ############################################################################### 8 | 9 | use warnings; 10 | use strict; 11 | 12 | use Test::More; 13 | 14 | use Socket qw/ $CRLF /; 15 | 16 | BEGIN { use FindBin; chdir($FindBin::Bin); } 17 | 18 | use lib 'lib'; 19 | use Test::Nginx; 20 | use Test::Nginx::Stream qw/ stream /; 21 | 22 | ############################################################################### 23 | 24 | select STDERR; $| = 1; 25 | select STDOUT; $| = 1; 26 | 27 | my $t = Test::Nginx->new(); 28 | 29 | $t->write_file_expand('nginx.conf', <<'EOF'); 30 | 31 | %%TEST_GLOBALS%% 32 | 33 | daemon off; 34 | 35 | # load_module /tmp/nginx/modules/ngx_stream_ipdb_module.so; 36 | 37 | events { 38 | } 39 | 40 | stream { 41 | set_real_ip_from 127.0.0.1/32; 42 | 43 | ipdb ./ipiptest.ipdb; 44 | ipdb_language CN; 45 | 46 | server { 47 | listen 127.0.0.1:8091 proxy_protocol; 48 | 49 | return "country_name:$ipdb_country_name 50 | region_name:$ipdb_region_name 51 | city_name:$ipdb_city_name 52 | isp_domain:$ipdb_isp_domain 53 | ipdb_raw:$ipdb_raw"; 54 | } 55 | } 56 | 57 | EOF 58 | 59 | $t->try_run('no ipdb')->plan(5); 60 | 61 | ############################################################################### 62 | 63 | my %data = stream_pp('36.102.4.81') =~ /(\w+):(.*)/g; 64 | is($data{country_name}, '中国', 'ipdb country name'); 65 | is($data{region_name}, '内蒙古', 'ipdb region name'); 66 | is($data{city_name}, '呼和浩特', 'ipdb city name'); 67 | is($data{isp_domain}, '', 'ipdb isp domain'); 68 | is($data{ipdb_raw}, "中国\t内蒙古\t呼和浩特", 'ipdb raw'); 69 | 70 | ############################################################################### 71 | 72 | sub stream_pp { 73 | my ($ip) = @_; 74 | my $type = ($ip =~ ':' ? 'TCP6' : 'TCP4'); 75 | return stream('127.0.0.1:' . port(8091)) 76 | ->io("PROXY $type $ip 127.0.0.1 8091 8091${CRLF}"); 77 | } 78 | 79 | ############################################################################### 80 | 81 | -------------------------------------------------------------------------------- /ngx_stream_ipdb_lua.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) vislee 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "ngx_stream_ipdb_module.h" 9 | #include "ngx_stream_ipdb_lua.h" 10 | 11 | // #include "ngx_stream_lua_api.h" 12 | #include "ngx_stream_lua_request.h" 13 | #include "ngx_stream_lua_util.h" 14 | 15 | static int 16 | ngx_stream_ipdb_get_raw(lua_State *L) 17 | { 18 | char body[512]; 19 | ngx_int_t err; 20 | ngx_str_t ip, v; 21 | ngx_addr_t addr; 22 | ngx_stream_lua_request_t *r; 23 | ngx_stream_ipdb_srv_conf_t *iscf; 24 | ngx_stream_ipdb_main_conf_t *imcf; 25 | 26 | 27 | r = ngx_stream_lua_get_request(L); 28 | if (r == NULL) { 29 | return luaL_error(L, "no request object found"); 30 | } 31 | 32 | iscf = ngx_stream_lua_get_module_srv_conf(r, ngx_stream_ipdb_module); 33 | imcf = ngx_stream_lua_get_module_main_conf(r, ngx_stream_ipdb_module); 34 | 35 | if (lua_type(L, -1) != LUA_TSTRING) { 36 | return luaL_error(L, "bad addr"); 37 | } 38 | 39 | ip.data = (u_char *) luaL_checklstring(L, 1, &ip.len); 40 | 41 | if (ngx_parse_addr(r->connection->pool, &addr, ip.data, ip.len) != NGX_OK) { 42 | return luaL_error(L, "bad addr format"); 43 | } 44 | 45 | err = ngx_stream_ipdb_item_by_addr(imcf->ipdb, &addr, 46 | (const char *)iscf->lang.data, body); 47 | if (err) { 48 | return luaL_error(L, "bad addr info"); 49 | } 50 | 51 | v.len = ngx_strlen(body); 52 | v.data = ngx_palloc(r->connection->pool, v.len); 53 | if (v.data == NULL) { 54 | return luaL_error(L, "no memory"); 55 | } 56 | ngx_memcpy(v.data, body, v.len); 57 | 58 | lua_pushlstring(L, (const char *) v.data, (size_t) v.len); 59 | return 1; 60 | } 61 | 62 | 63 | static int 64 | ngx_stream_ipdb_lua_register(lua_State *L) 65 | { 66 | lua_createtable(L, 0, 1); 67 | 68 | lua_pushcfunction(L, ngx_stream_ipdb_get_raw); 69 | lua_setfield(L, -2, "get_raw"); 70 | 71 | return 1; 72 | } 73 | 74 | 75 | ngx_int_t 76 | ngx_stream_ipdb_lua_preload(ngx_conf_t *cf) 77 | { 78 | if (ngx_stream_lua_add_package_preload(cf, "ngx.stream.ipdb", 79 | ngx_stream_ipdb_lua_register) 80 | != NGX_OK) 81 | { 82 | return NGX_ERROR; 83 | } 84 | 85 | return NGX_OK; 86 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Name 2 | ==== 3 | 4 | 5 | [![Build Status](https://travis-ci.org/vislee/ngx_stream_ipdb_module.svg?branch=master)](https://travis-ci.org/vislee/ngx_stream_ipdb_module) 6 | [![Coverage Status](https://coveralls.io/repos/github/vislee/ngx_stream_ipdb_module/badge.svg?branch=master)](https://coveralls.io/github/vislee/ngx_stream_ipdb_module?branch=master) 7 | 8 | ngx_stream_ipdb_module - creates variables with values depending on the client IP address, using the precompiled [ipip.net](https://www.ipip.net) [ipdb](https://www.ipip.net/ipdb/test). 9 | 10 | 11 | Table of Contents 12 | ================= 13 | * [Name](#name) 14 | * [Status](#status) 15 | * [Install](#install) 16 | * [Example Configuration](#example-configuration) 17 | * [Directives](#directives) 18 | * [ipdb](#ipdb) 19 | * [ipdb_language](#ipdb_language) 20 | * [Variable](#variable) 21 | * [$ipdb_country_name](#ipdb_country_name) 22 | * [$ipdb_region_name](#ipdb_region_name) 23 | * [$ipdb_city_name](#ipdb_city_name) 24 | * [$ipdb_isp_domain](#ipdb_isp_domain) 25 | * [$ipdb_raw](#ipdb_raw) 26 | * [Lua API](#lua_api) 27 | * [get_raw](#get_raw) 28 | * [TODO](#todo) 29 | * [Author](#author) 30 | * [Copyright and License](#copyright-and-license) 31 | * [See Also](#see-also) 32 | 33 | 34 | Status 35 | ====== 36 | The module is currently in active development. 37 | 38 | [Back to TOC](#table-of-contents) 39 | 40 | Install 41 | ======= 42 | 43 | ```sh 44 | # install json-c lib 45 | # centos 46 | yum install json-c-devel -y 47 | #or mac OSX 48 | brew install json-c 49 | 50 | configure --prefix=/usr/local/nginx --with-stream --add-module=./github.com/vislee/ngx_stream_ipdb_module 51 | # or dynamic compile 52 | configure --prefix=/usr/local/nginx --with-stream --add-dynamic-module=./github.com/vislee/ngx_stream_ipdb_module --with-compat 53 | 54 | # or stream_lua 55 | configure --prefix=/usr/local/nginx --with-stream --add-module=./github.com/openresty/stream-lua-nginx-module/ --add-module=./github.com/vislee/ngx_stream_ipdb_module --with-cc-opt='-I ./github.com/openresty/stream-lua-nginx-module/src' 56 | ``` 57 | 58 | The following information is success: 59 | 60 | >> checking for json-c library ... found 61 | >> + ngx_stream_ipdb_module was configured 62 | 63 | 64 | [Back to TOC](#table-of-contents) 65 | 66 | Example Configuration 67 | ==================== 68 | 69 | ```nginx 70 | 71 | # load_module modules/ngx_stream_ipdb_module.so; 72 | 73 | stream { 74 | ipdb conf/ipiptest.ipdb; 75 | ipdb_language "CN"; 76 | 77 | server { 78 | listen 8091; 79 | # ipdb_language EN; 80 | 81 | return "country_name:$ipdb_country_name, raw_info:$ipdb_raw"; 82 | } 83 | 84 | # stream_lua 85 | server { 86 | listen 8092; 87 | ipdb_language CN; 88 | 89 | content_by_lua_block { 90 | local sipdb = require "ngx.stream.ipdb"; 91 | ngx.say(sipdb.get_raw("127.0.0.1")); 92 | } 93 | } 94 | } 95 | 96 | ``` 97 | 98 | [Back to TOC](#table-of-contents) 99 | 100 | TODO 101 | ========== 102 | 103 | [Back to TOC](#table-of-contents) 104 | 105 | Directives 106 | ========== 107 | 108 | ipdb 109 | ---- 110 | **syntax:** *ipdb file;* 111 | 112 | **default:** *-* 113 | 114 | **context:** *stream* 115 | 116 | Specifies a database. 117 | 118 | ipdb_language 119 | ------------- 120 | **syntax:** *ipdb_language EN|CN;* 121 | 122 | **default:** *EN* 123 | 124 | **context:** *stream,server* 125 | 126 | set variable language. 127 | 128 | 129 | [Back to TOC](#table-of-contents) 130 | 131 | 132 | Variable 133 | ======== 134 | 135 | ipdb_country_name 136 | ---------------- 137 | 138 | $ipdb_country_name - country name, for example, "中国", "China" 139 | 140 | ipdb_region_name 141 | ---------------- 142 | 143 | $ipdb_region_name - country region name, for example, "内蒙古","Nei Mongol", "北京", "Beijing" 144 | 145 | ipdb_city_name 146 | -------------- 147 | 148 | $ipdb_city_name - city name, for example, "呼和浩特", "Hohhot", "北京", "Beijing" 149 | 150 | ipdb_isp_domain 151 | --------------- 152 | 153 | $ipdb_isp_domain - ISP name, for example, "电信", "ChinaTelecom" 154 | 155 | ipdb_raw 156 | -------- 157 | 158 | $ipdb_raw - raw info, for example, "中国\t内蒙古\t呼和浩特","China\tNei Mongol\tHohhot" 159 | 160 | 161 | [Back to TOC](#table-of-contents) 162 | 163 | 164 | Lua API 165 | ======== 166 | 167 | get_raw 168 | ------- 169 | 170 | **syntax:** ipdb_raw = ngx.stream.ipdb.get_raw(addr) 171 | 172 | **context:** content_by_lua*, log_by_lua* 173 | 174 | Get raw info for `addr` . for example, "中国\t内蒙古\t呼和浩特","China\tNei Mongol\tHohhot" 175 | 176 | 177 | [Back to TOC](#table-of-contents) 178 | 179 | Author 180 | ====== 181 | 182 | wenqiang li(vislee) 183 | 184 | [Back to TOC](#table-of-contents) 185 | 186 | Copyright and License 187 | ===================== 188 | 189 | This module is licensed under the BSD 3-Clause License. 190 | 191 | Copyright (C) 2019, by vislee. 192 | 193 | All rights reserved. 194 | 195 | [Back to TOC](#table-of-contents) 196 | 197 | 198 | See Also 199 | ======== 200 | 201 | + [ngx_stream_geoip_module](http://nginx.org/en/docs/stream/ngx_stream_geoip_module.html) 202 | + [github.com/ipipdotnet/ipdb-c](https://github.com/ipipdotnet/ipdb-c) 203 | + [ngx_http_ipdb_module](https://github.com/vislee/ngx_http_ipdb_module) 204 | -------------------------------------------------------------------------------- /ipdb/ipdb.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by root on 11/14/18. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "ipdb.h" 10 | 11 | int is_big_endian(void) { 12 | union { 13 | uint32_t i; 14 | char c[4]; 15 | } e = {0x01000000}; 16 | 17 | return e.c[0]; 18 | } 19 | 20 | unsigned int l2b(unsigned int x) { 21 | return (((x >> 24) & 0x000000ff) | ((x >> 8) & 0x0000ff00) | ((x << 8) & 0x00ff0000) | ((x << 24) & 0xff000000)); 22 | } 23 | 24 | ipdb_meta_data *parse_meta_data(const char *meta_json) { 25 | int i = 0; 26 | 27 | ipdb_meta_data *meta_data = (ipdb_meta_data *) malloc(sizeof(ipdb_meta_data)); 28 | if (meta_data == NULL) { 29 | return NULL; 30 | } 31 | 32 | memset(meta_data, 0, sizeof(ipdb_meta_data)); 33 | 34 | json_object *obj = json_tokener_parse(meta_json); 35 | json_object *value = NULL; 36 | 37 | if (json_object_object_get_ex(obj, "node_count", &value)) { 38 | meta_data->node_count = json_object_get_int(value); 39 | } 40 | 41 | if (json_object_object_get_ex(obj, "total_size", &value)) { 42 | meta_data->total_size = json_object_get_int(value); 43 | } 44 | 45 | if (json_object_object_get_ex(obj, "build", &value)){ 46 | meta_data->build_time = json_object_get_int64(value); 47 | } 48 | 49 | if (json_object_object_get_ex(obj, "ip_version", &value)) { 50 | meta_data->ip_version = (short) json_object_get_int(value); 51 | } 52 | 53 | if (json_object_object_get_ex(obj, "fields", &value)) { 54 | meta_data->fields_length = json_object_array_length(value); 55 | } 56 | 57 | meta_data->fields = (char **) malloc(sizeof(char *) * meta_data->fields_length); 58 | if (meta_data->fields == NULL) { 59 | return NULL; 60 | } 61 | for (i = 0; i < meta_data->fields_length; ++i) { 62 | json_object *it = json_object_array_get_idx(value, i); 63 | meta_data->fields[i] = malloc(sizeof(char) * json_object_get_string_len(it) + 1); 64 | strcpy(meta_data->fields[i], json_object_get_string(it)); 65 | } 66 | 67 | if (json_object_object_get_ex(obj, "languages", &value)) { 68 | meta_data->language_length = json_object_object_length(value); 69 | meta_data->language = (ipdb_meta_data_language *) malloc( 70 | sizeof(ipdb_meta_data_language) * meta_data->language_length); 71 | if (meta_data->language == NULL) { 72 | return NULL; 73 | } 74 | 75 | struct json_object_iterator language = json_object_iter_begin(value); 76 | for (i = 0; i < meta_data->language_length; ++i) { 77 | strcpy(meta_data->language[i].name, json_object_iter_peek_name(&language)); 78 | struct json_object *it = json_object_iter_peek_value(&language); 79 | meta_data->language[i].offset = json_object_get_int(it); 80 | json_object_iter_next(&language); 81 | } 82 | json_object_iter_end(value); 83 | } 84 | 85 | return meta_data; 86 | } 87 | 88 | int ipdb_read_node(ipdb_reader *reader, int node, int index) { 89 | int off = node * 8 + index * 4; 90 | int tar = *(int *) &reader->data[off]; 91 | return l2b((unsigned int) tar); 92 | } 93 | 94 | int ipdb_reader_new(const char *file, ipdb_reader **reader) { 95 | FILE *fd = fopen(file, "rb"); 96 | if (!fd) { 97 | return ErrFileSize; 98 | } 99 | *reader = malloc(sizeof(ipdb_reader)); 100 | ipdb_reader *rd = *reader; 101 | 102 | fseek(fd, 0, SEEK_END); 103 | long fsize = ftell(fd); 104 | fseek(fd, 0, SEEK_SET); 105 | unsigned int meta_length = 0; 106 | fread(&meta_length, sizeof(meta_length), 1, fd); 107 | meta_length = is_big_endian() ? meta_length : l2b(meta_length); 108 | 109 | char *meta_json = (char *) malloc(meta_length + 1); 110 | meta_json[meta_length] = 0; 111 | fread(meta_json, sizeof(char), meta_length, fd); 112 | rd->meta = parse_meta_data(meta_json); 113 | free(meta_json); 114 | if (rd->meta == NULL || rd->meta->language_length == 0 || rd->meta->fields_length == 0) { 115 | return ErrMetaData; 116 | } 117 | 118 | if (fsize != (4 + meta_length + rd->meta->total_size)) { 119 | return ErrFileSize; 120 | } 121 | rd->file_size = (int) fsize; 122 | int data_len = (int) fsize - 4 - meta_length; 123 | rd->data = (unsigned char *) malloc(sizeof(unsigned char) * data_len); 124 | fread(rd->data, sizeof(unsigned char), (size_t) data_len, fd); 125 | rd->data_size = data_len; 126 | 127 | int node = 0; 128 | int i = 0; 129 | for (i = 0; i < 96 && node < rd->meta->node_count; ++i) { 130 | if (i >= 80) { 131 | node = ipdb_read_node(rd, node, 1); 132 | } else { 133 | node = ipdb_read_node(rd, node, 0); 134 | } 135 | } 136 | rd->v4offset = node; 137 | 138 | fclose(fd); 139 | return ErrNoErr; 140 | } 141 | 142 | void ipdb_reader_free(ipdb_reader **reader) { 143 | int i = 0; 144 | if ((*reader)->meta) { 145 | ipdb_meta_data *meta_data = (*reader)->meta; 146 | for (i = 0; i < meta_data->fields_length; ++i) { 147 | free(meta_data->fields[i]); 148 | } 149 | free(meta_data->fields); 150 | free(meta_data->language); 151 | free(meta_data); 152 | } 153 | if ((*reader)->data) { 154 | free((*reader)->data); 155 | } 156 | free(*reader); 157 | *reader = 0; 158 | } 159 | 160 | int ipdb_reader_is_ipv4_support(ipdb_reader *reader) { 161 | return (((int) reader->meta->ip_version) & IPv4) == IPv4; 162 | 163 | } 164 | 165 | int ipdb_reader_is_ipv6_support(ipdb_reader *reader) { 166 | return (((int) reader->meta->ip_version) & IPv6) == IPv6; 167 | 168 | } 169 | 170 | int ipdb_resolve(ipdb_reader *reader, int node, const char **bytes) { 171 | int resolved = node - reader->meta->node_count + reader->meta->node_count * 8; 172 | if (resolved >= reader->file_size) { 173 | return ErrDatabaseError; 174 | } 175 | 176 | int size = (reader->data[resolved] << 8) | reader->data[resolved + 2]; 177 | if ((resolved + 2 + size) > reader->data_size) { 178 | return ErrDatabaseError; 179 | } 180 | *bytes = (const char *) reader->data + resolved + 2; 181 | return ErrNoErr; 182 | } 183 | 184 | int ipdb_search(ipdb_reader *reader, const u_char *ip, int bit_count, int *node) { 185 | int i = 0; 186 | 187 | *node = 0; 188 | 189 | if (bit_count == 32) { 190 | *node = reader->v4offset; 191 | } else { 192 | *node = 0; 193 | } 194 | 195 | for (i = 0; i < bit_count; ++i) { 196 | if (*node > reader->meta->node_count) { 197 | break; 198 | } 199 | 200 | *node = ipdb_read_node(reader, *node, 201 | ((0xFF & ((int) ip[i >> 3])) >> (unsigned int) (7 - (i % 8))) & 1); 202 | } 203 | 204 | if (*node > reader->meta->node_count) { 205 | return ErrNoErr; 206 | } 207 | return ErrDataNotExists; 208 | } 209 | 210 | int ipdb_find0(ipdb_reader *reader, const char *addr, const char **body) { 211 | int node = 0; 212 | int err; 213 | struct in_addr addr4; 214 | struct in6_addr addr6; 215 | if (inet_pton(AF_INET, addr, &addr4)) { 216 | if (!ipdb_reader_is_ipv4_support(reader)) { 217 | return ErrNoSupportIPv4; 218 | } 219 | err = ipdb_search(reader, (const u_char *) &addr4.s_addr, 32, &node); 220 | if (err != ErrNoErr) { 221 | return err; 222 | } 223 | } else if (inet_pton(AF_INET6, addr, &addr6)) { 224 | if (!ipdb_reader_is_ipv6_support(reader)) { 225 | return ErrNoSupportIPv6; 226 | } 227 | err = ipdb_search(reader, (const u_char *) &addr6.s6_addr, 128, &node); 228 | if (err != ErrNoErr) { 229 | return err; 230 | } 231 | } else { 232 | return ErrIPFormat; 233 | } 234 | err = ipdb_resolve(reader, node, body); 235 | return err; 236 | } 237 | 238 | int ipdb_find1(ipdb_reader *reader, const char *addr, const char *language, char *body) { 239 | int err, i; 240 | off_t off = -1; 241 | for (i = 0; i < reader->meta->language_length; ++i) { 242 | if (strcmp(language, reader->meta->language[i].name) == 0) { 243 | off = reader->meta->language[i].offset; 244 | break; 245 | } 246 | } 247 | if (off == -1) { 248 | return ErrNoSupportLanguage; 249 | } 250 | const char *content; 251 | err = ipdb_find0(reader, addr, &content); 252 | if (err != ErrNoErr) { 253 | return err; 254 | } 255 | size_t p = 0, o = 0, s = 0, e = 0; 256 | size_t len = reader->meta->fields_length; 257 | 258 | while (*(content + p)) { 259 | if (*(content + p) == '\t') { 260 | ++o; 261 | } 262 | if ((!e) && o == off + len) { 263 | e = p; 264 | } 265 | ++p; 266 | if (off && (!s) && (off_t)o == off) { 267 | s = p; 268 | } 269 | } 270 | if (!e) e = p; 271 | if (off + len > o + 1) { 272 | err = ErrDatabaseError; 273 | } else { 274 | strncpy(body, content + s, e - s); 275 | body[e - s] = 0; 276 | } 277 | return err; 278 | } 279 | 280 | int ipdb_reader_find(ipdb_reader *reader, const char *addr, const char *language, char *body) { 281 | return ipdb_find1(reader, addr, language, body); 282 | } -------------------------------------------------------------------------------- /ngx_stream_ipdb_module.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) vislee 3 | */ 4 | 5 | #include "ngx_stream_ipdb_module.h" 6 | 7 | #ifdef NGX_STREAM_IPDB_LUA 8 | #include "ngx_stream_ipdb_lua.h" 9 | #endif 10 | 11 | 12 | #define NGX_IPDB_country_name 0 13 | #define NGX_IPDB_region_name 1 14 | #define NGX_IPDB_city_name 2 15 | #define NGX_IPDB_owner_domain 3 16 | #define NGX_IPDB_isp_domain 4 17 | #define NGX_IPDB_latitude 5 18 | #define NGX_IPDB_longitude 6 19 | // all item 20 | #define NGX_IPDB_raw 20 21 | 22 | 23 | static ngx_int_t ngx_stream_ipdb_variable(ngx_stream_session_t *s, 24 | ngx_stream_variable_value_t *v, uintptr_t data); 25 | static ngx_int_t ngx_stream_ipdb_init(ngx_conf_t *cf); 26 | static ngx_int_t ngx_stream_ipdb_add_variables(ngx_conf_t *cf); 27 | static char *ngx_stream_ipdb_language(ngx_conf_t *cf, void *post, void *data); 28 | static void *ngx_stream_ipdb_create_main_conf(ngx_conf_t *cf); 29 | static void *ngx_stream_ipdb_create_srv_conf(ngx_conf_t *cf); 30 | static char *ngx_stream_ipdb_merge_srv_conf(ngx_conf_t *cf, void *parent, 31 | void *child); 32 | static void ngx_stream_ipdb_cleanup(void *data); 33 | static char *ngx_stream_ipdb_open(ngx_conf_t *cf, ngx_command_t *cmd, 34 | void *conf); 35 | 36 | 37 | static ngx_conf_post_handler_pt ngx_stream_ipdb_language_p = 38 | ngx_stream_ipdb_language; 39 | 40 | 41 | static ngx_command_t ngx_stream_ipdb_commands[] = { 42 | 43 | { ngx_string("ipdb"), 44 | NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1, 45 | ngx_stream_ipdb_open, 46 | NGX_STREAM_MAIN_CONF_OFFSET, 47 | 0, 48 | NULL }, 49 | 50 | { ngx_string("ipdb_language"), 51 | NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, 52 | ngx_conf_set_str_slot, 53 | NGX_STREAM_SRV_CONF_OFFSET, 54 | offsetof(ngx_stream_ipdb_srv_conf_t, lang), 55 | &ngx_stream_ipdb_language_p }, 56 | 57 | ngx_null_command 58 | }; 59 | 60 | 61 | static ngx_stream_module_t ngx_stream_ipdb_module_ctx = { 62 | ngx_stream_ipdb_add_variables, /* preconfiguration */ 63 | ngx_stream_ipdb_init, /* postconfiguration */ 64 | 65 | ngx_stream_ipdb_create_main_conf, /* create main configuration */ 66 | NULL, /* init main configuration */ 67 | 68 | ngx_stream_ipdb_create_srv_conf, /* create server configuration */ 69 | ngx_stream_ipdb_merge_srv_conf /* merge server configuration */ 70 | }; 71 | 72 | 73 | ngx_module_t ngx_stream_ipdb_module = { 74 | NGX_MODULE_V1, 75 | &ngx_stream_ipdb_module_ctx, /* module context */ 76 | ngx_stream_ipdb_commands, /* module directives */ 77 | NGX_STREAM_MODULE, /* module type */ 78 | NULL, /* init master */ 79 | NULL, /* init module */ 80 | NULL, /* init process */ 81 | NULL, /* init thread */ 82 | NULL, /* exit thread */ 83 | NULL, /* exit process */ 84 | NULL, /* exit master */ 85 | NGX_MODULE_V1_PADDING 86 | }; 87 | 88 | 89 | static ngx_stream_variable_t ngx_stream_ipdb_vars[] = { 90 | { ngx_string("ipdb_country_name"), NULL, 91 | ngx_stream_ipdb_variable, 92 | NGX_IPDB_country_name, 0, 0 }, 93 | 94 | { ngx_string("ipdb_region_name"), NULL, 95 | ngx_stream_ipdb_variable, 96 | NGX_IPDB_region_name, 0, 0 }, 97 | 98 | { ngx_string("ipdb_city_name"), NULL, 99 | ngx_stream_ipdb_variable, 100 | NGX_IPDB_city_name, 0, 0 }, 101 | 102 | { ngx_string("ipdb_isp_domain"), NULL, 103 | ngx_stream_ipdb_variable, 104 | NGX_IPDB_isp_domain, 0, 0 }, 105 | 106 | { ngx_string("ipdb_raw"), NULL, 107 | ngx_stream_ipdb_variable, 108 | NGX_IPDB_raw, 0, 0 }, 109 | 110 | ngx_stream_null_variable 111 | }; 112 | 113 | 114 | static ngx_int_t 115 | ngx_stream_ipdb_add_variables(ngx_conf_t *cf) 116 | { 117 | ngx_stream_variable_t *var, *v; 118 | 119 | for (v = ngx_stream_ipdb_vars; v->name.len; v++) { 120 | var = ngx_stream_add_variable(cf, &v->name, v->flags); 121 | if (var == NULL) { 122 | return NGX_ERROR; 123 | } 124 | 125 | var->get_handler = v->get_handler; 126 | var->data = v->data; 127 | } 128 | 129 | return NGX_OK; 130 | } 131 | 132 | 133 | static ngx_int_t 134 | ngx_stream_ipdb_init(ngx_conf_t *cf) 135 | { 136 | 137 | #ifdef NGX_STREAM_IPDB_LUA 138 | return ngx_stream_ipdb_lua_preload(cf); 139 | #endif 140 | 141 | return NGX_OK; 142 | } 143 | 144 | 145 | static void * 146 | ngx_stream_ipdb_create_main_conf(ngx_conf_t *cf) 147 | { 148 | ngx_pool_cleanup_t *cln; 149 | ngx_stream_ipdb_main_conf_t *conf; 150 | 151 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_ipdb_main_conf_t)); 152 | if (conf == NULL) { 153 | return NULL; 154 | } 155 | 156 | cln = ngx_pool_cleanup_add(cf->pool, 0); 157 | if (cln == NULL) { 158 | return NULL; 159 | } 160 | 161 | cln->handler = ngx_stream_ipdb_cleanup; 162 | cln->data = conf; 163 | 164 | return conf; 165 | } 166 | 167 | 168 | static void * 169 | ngx_stream_ipdb_create_srv_conf(ngx_conf_t *cf) 170 | { 171 | ngx_stream_ipdb_srv_conf_t *conf; 172 | 173 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_ipdb_srv_conf_t)); 174 | if (conf == NULL) { 175 | return NULL; 176 | } 177 | 178 | return conf; 179 | } 180 | 181 | 182 | static char * 183 | ngx_stream_ipdb_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) 184 | { 185 | ngx_stream_ipdb_srv_conf_t *prev = parent; 186 | ngx_stream_ipdb_srv_conf_t *conf = child; 187 | 188 | ngx_conf_merge_str_value(conf->lang, prev->lang, "EN"); 189 | 190 | return NGX_CONF_OK; 191 | } 192 | 193 | 194 | static char * 195 | ngx_stream_ipdb_open(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 196 | { 197 | ngx_int_t err; 198 | ngx_stream_ipdb_main_conf_t *imcf = conf; 199 | 200 | ngx_str_t *value; 201 | 202 | if (imcf->ipdb) { 203 | return "is duplicate"; 204 | } 205 | 206 | value = cf->args->elts; 207 | 208 | err = ipdb_reader_new((char *) value[1].data, &imcf->ipdb); 209 | 210 | if (err || imcf->ipdb == NULL) { 211 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 212 | "ipdb_reader_new(\"%V\") failed", &value[1]); 213 | 214 | return NGX_CONF_ERROR; 215 | } 216 | 217 | return NGX_CONF_OK; 218 | } 219 | 220 | 221 | static char * 222 | ngx_stream_ipdb_language(ngx_conf_t *cf, void *post, void *data) 223 | { 224 | ngx_str_t *lang = data; 225 | 226 | if (ngx_strcmp(lang->data, "EN") == 0 227 | || ngx_strcmp(lang->data, "CN") == 0) { 228 | 229 | return NGX_CONF_OK; 230 | } 231 | 232 | return NGX_CONF_ERROR; 233 | } 234 | 235 | 236 | static char * 237 | ngx_stream_ipdb_get_index_item(char *v, ngx_int_t idx) 238 | { 239 | char *p, *q; 240 | ngx_int_t n = 0; 241 | 242 | if (v == NULL) return NULL; 243 | 244 | if (idx >= NGX_IPDB_raw) return v; 245 | 246 | p = v; 247 | q = p; 248 | 249 | while (*p) { 250 | 251 | if (*p == '\t') { 252 | 253 | if (idx == n) { 254 | *p = 0; 255 | return q; 256 | } 257 | 258 | q = p + 1; 259 | ++n; 260 | } 261 | 262 | ++p; 263 | } 264 | 265 | if (*p == 0 && idx == n) { 266 | return q; 267 | } 268 | 269 | return NULL; 270 | } 271 | 272 | 273 | ngx_int_t 274 | ngx_stream_ipdb_item_by_addr(ipdb_reader *reader, ngx_addr_t *addr, 275 | const char *lang, char *body) 276 | { 277 | int node = 0; 278 | ngx_int_t err, i; 279 | off_t off = -1; 280 | size_t p = 0, o = 0, s = 0, e = 0; 281 | size_t len = reader->meta->fields_length; 282 | const char *content; 283 | 284 | for (i = 0; i < reader->meta->language_length; ++i) { 285 | if (ngx_strcmp(lang, reader->meta->language[i].name) == 0) { 286 | off = reader->meta->language[i].offset; 287 | break; 288 | } 289 | } 290 | 291 | if (off == -1) { 292 | return ErrNoSupportLanguage; 293 | } 294 | 295 | if (addr->sockaddr->sa_family == AF_INET) { 296 | if (!ipdb_reader_is_ipv4_support(reader)) { 297 | return ErrNoSupportIPv4; 298 | } 299 | 300 | struct sockaddr_in *sin; 301 | 302 | sin = (struct sockaddr_in *) addr->sockaddr; 303 | // sin->sin_addr.s_addr 304 | err = ipdb_search(reader, (const u_char *)&sin->sin_addr.s_addr, 32, &node); 305 | if (err != ErrNoErr) { 306 | return err; 307 | } 308 | } 309 | #if (NGX_HAVE_INET6) 310 | else if (addr->sockaddr->sa_family == AF_INET6) { 311 | if (!ipdb_reader_is_ipv6_support(reader)) { 312 | return ErrNoSupportIPv6; 313 | } 314 | 315 | struct in6_addr *inaddr6; 316 | inaddr6 = &((struct sockaddr_in6 *) addr->sockaddr)->sin6_addr; 317 | err = ipdb_search(reader, (const u_char *)&inaddr6->s6_addr, 128, &node); 318 | if (err != ErrNoErr) { 319 | return err; 320 | } 321 | } 322 | #endif 323 | else { 324 | return ErrIPFormat; 325 | } 326 | 327 | err = ipdb_resolve(reader, node, &content); 328 | if (err) { 329 | return err; 330 | } 331 | 332 | while (*(content + p)) { 333 | if (*(content + p) == '\t') { 334 | ++o; 335 | } 336 | if ((!e) && o == off + len) { 337 | e = p; 338 | } 339 | ++p; 340 | if (off && (!s) && (off_t)o == off) { 341 | s = p; 342 | } 343 | } 344 | if (!e) e = p; 345 | if (off + len > o + 1) { 346 | err = ErrDatabaseError; 347 | } else { 348 | strncpy(body, content + s, e - s); 349 | body[e - s] = 0; 350 | } 351 | 352 | return err; 353 | } 354 | 355 | 356 | static ngx_int_t 357 | ngx_stream_ipdb_variable(ngx_stream_session_t *s, 358 | ngx_stream_variable_value_t *v, uintptr_t data) 359 | { 360 | char *p; 361 | char body[512]; 362 | ngx_int_t err; 363 | ngx_addr_t addr; 364 | ngx_stream_ipdb_srv_conf_t *iscf; 365 | ngx_stream_ipdb_main_conf_t *imcf; 366 | 367 | #if (NGX_DEBUG) 368 | ngx_str_t debug; 369 | #endif 370 | 371 | imcf = ngx_stream_get_module_main_conf(s, ngx_stream_ipdb_module); 372 | 373 | if (imcf == NULL || imcf->ipdb == NULL) { 374 | goto not_found; 375 | } 376 | 377 | iscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ipdb_module); 378 | 379 | addr.sockaddr = s->connection->sockaddr; 380 | addr.socklen = s->connection->socklen; 381 | 382 | err = ngx_stream_ipdb_item_by_addr(imcf->ipdb, &addr, 383 | (const char *)iscf->lang.data, body); 384 | if (err) { 385 | ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, 386 | "ngx_stream_ipdb_variable, ipdb find error: %d", err); 387 | 388 | goto not_found; 389 | } 390 | 391 | #if (NGX_DEBUG) 392 | debug.len = ngx_strlen(body); 393 | debug.data = (u_char *)body; 394 | ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, 395 | "ngx_stream_ipdb_variable, item: \"%V\"", &debug); 396 | #endif 397 | 398 | p = ngx_stream_ipdb_get_index_item(body, data); 399 | if (p == NULL) { 400 | goto not_found; 401 | } 402 | 403 | v->len = ngx_strlen(p); 404 | v->data = ngx_pnalloc(s->connection->pool, v->len); 405 | if (v->data == NULL) { 406 | return NGX_ERROR; 407 | } 408 | 409 | ngx_memcpy(v->data, p, v->len); 410 | 411 | v->valid = 1; 412 | v->no_cacheable = 0; 413 | v->not_found = 0; 414 | 415 | return NGX_OK; 416 | 417 | not_found: 418 | 419 | v->not_found = 1; 420 | 421 | return NGX_OK; 422 | } 423 | 424 | 425 | static void 426 | ngx_stream_ipdb_cleanup(void *data) 427 | { 428 | ngx_stream_ipdb_main_conf_t *imcf = data; 429 | 430 | if (imcf->ipdb) { 431 | ipdb_reader_free(&imcf->ipdb); 432 | } 433 | } 434 | --------------------------------------------------------------------------------