
一、背景
二、解决方案
三、参考
《openresty基于lua/geoIp/redis实现ip限制》中介绍了基于geoIp库识别ip所属国家信息从而进行ip过滤和限制,目前有诉求需要追溯的ip服务商的信息进行过滤,比如识别到ip提供商是亚马逊机房,那么进行限制。
当然geopIp2也提供了ISP产品能力,来识别ip服务商,但是他是付费的,没有免费版本。

调研到国内开源的ip2region是免费的并且提供了ip归属地查询以及服务商信息查询能力。解析出来格式是
国家|区域|省份|城市|ISP,只有中国的数据绝大部分精确到了城市,其他国家部分数据只能定位到国家,后边的选项全部是0。
ip2region数据聚合了一些知名ip到地名查询提供商的数据,这些是他们官方的的准确率,经测试着实比经典的纯真IP定位准确一些。 ip2region的数据聚合自以下服务商的开放API或者数据(升级程序每秒请求次数2到4次):
已经支持了以下客户端集成:
binding | 描述 | 开发状态 | binary查询耗时 | b-tree查询耗时 | memory查询耗时 |
|---|---|---|---|---|---|
c | ANSC c binding | 已完成 | 0.0x毫秒 | 0.0x毫秒 | 0.00x毫秒 |
c# | c# binding | 已完成 | 0.x毫秒 | 0.x毫秒 | 0.1x毫秒 |
golang | golang binding | 已完成 | 0.x毫秒 | 0.x毫秒 | 0.1x毫秒 |
java | java binding | 已完成 | 0.x毫秒 | 0.x毫秒 | 0.1x毫秒 |
lua | lua实现的binding | 已完成 | 0.x毫秒 | 0.x毫秒 | 0.x毫秒 |
lua_c | lua的c扩展 | 已完成 | 0.0x毫秒 | 0.0x毫秒 | 0.00x毫秒 |
nginx | nginx的c扩展 | 已完成 | 0.0x毫秒 | 0.0x毫秒 | 0.00x毫秒 |
nodejs | nodejs | 已完成 | 0.x毫秒 | 0.x毫秒 | 0.1x毫秒 |
php | php实现的binding | 已完成 | 0.x毫秒 | 0.1x毫秒 | 0.1x毫秒 |
php5_ext | php5的c扩展 | 已完成 | 0.0x毫秒 | 0.0x毫秒 | 0.00x毫秒 |
php7_ext | php7的c扩展 | 已完成 | 0.0毫秒 | 0.0x毫秒 | 0.00x毫秒 |
python | python bindng | 已完成 | 0.x毫秒 | 0.x毫秒 | 0.x毫秒 |
rust | rust binding | 已完成 | 0.x毫秒 | 0.x毫秒 | 0.x毫秒 |
我们计划使用lua_c客户端集成,来实现openresty对ip2region操作。这里介绍下Openresty采用LuaJit,目前套件中使用的LuaJit2.1对应的Lua5.1版本,固然ip2region的Lua(Ip2region模块的位运算依赖了bit32模块,这个是lua 5.2才开始支持的。)是不能直接使用的。LuaJit安装目录/usr/local/openresty/luajit/include/luajit-2.1。
下载ip2region源码:
cd /opt/tools/
git clone https://github.com/lionsoul2014/ip2region.git
cd /opt/tools/ip2region/v1.0/binding我们需要编译binding目录下c和lua_c模块

修改lua_c的Makefile文件并编译安装:
CC = gcc
LIBS = -I ../c/ -I /usr/local/openresty/luajit/include/luajit-2.1
FFLAGS = -O2 -Wall -fPIC
SO_FILE = Ip2region.so
LIB_DIR = /usr/local/lib/lua/5.1
make
make installlua_c依赖c模块,进入c目录执行编译安装:
cd /opt/tools/ip2region/v1.0/binding/c
make
make install将ip2region库文件拷贝到openresty配置目录:
cp /opt/tools/ip2region/v1.0/data/ip2region.db /usr/local/openresty/nginx/conf/
编写lua脚本:
local cjson=require 'cjson'
local ip = ngx.var.arg_ip
local Ip2region,err = require "Ip2region";
if not Ip2region then
ngx.log(ngx.ERR,"require Ip2region error: ", err);
ngx.print("require Ip2region error: ", err);
else
local ip2region,err = Ip2region.new("/usr/local/openresty/nginx/conf/ip2region.db");
if not ip2region then
ngx.log(ngx.ERR,"require Ip2region error: ", err);
ngx.print("require Ip2region error: ", err);
else
local data,err = ip2region:memorySearch(ip);
if not data then
ngx.print("require Ip2region data error: ", err);
ngx.log(ngx.ERR,"require Ip2region data error: ", err);
else
ngx.print(cjson.encode(data));
end
end
end编写location:
location /ip2region {
default_type 'text/plain';
content_by_lua_file /usr/local/openresty/nginx/conf/lua/ip2region.lua;
}先重新加载配置:
nginx -s reload查询:
curl localhost:8089/ip2region?ip=18.143.139.87
返回数据的最后|分隔符后边就是ISP。
如果需要限制ip服务商,那么在解析出来ISP后,修改lua脚本对比规则返回对应的结果即可。
https://github.com/lionsoul2014/ip2region/tree/master/v1.0/binding/lua_c
http://www.180716.xyz/nginx/nginx/ip2region_lua_c.shtml
https://www.maxmind.com/en/geoip2-isp-database#features