目录

Nginx实现ip查询服务

实现内部IP查询服务

  • 查询当前公网IP
  • 查询当前公网IP地理信息,支持IPv4/IPv6
  • 查询指定IP的地理信息,支持IPv4/IPv6

环境

配置

lua_shared_dict ip_data 10m;

server {
    server_name ip.test.com;
    access_log logs/ip.access.log main buffer=32k flush=10s;
    error_log logs/ip.error.log;

    location / {
        default_type 'text/plain';
        access_by_lua_block {
            local remote_addr = ngx.var.remote_addr
            ngx.print(remote_addr)
        }
    }

    location = /ip {
        default_type application/json;
        content_by_lua_block {
            local require = require
            local ngx = ngx
            local cjson = require "cjson.safe"
            local json_encode = cjson.encode
            local ip2region = require "resty.ip2region"
            local ipmatcher = require "resty.ipmatcher"
            local geo = require "resty.maxminddb"
            local location = ip2region.new({
                file = "/data/nginx/lua/ip/ip2region.db",
                dict = "ip_data",
                mode = "memory" -- maybe memory,binary or btree
            })
            if not geo.initted() then
                geo.init("/data/nginx/lua/ip/GeoLite2-City.mmdb")
            end

            local remote_addr = ngx.var.arg_ip or ngx.var.remote_addr

            local ip_detail = {
                ip=remote_addr,
                country=0,
                province=0,
                city=0,
                isp=0,
            }
            local is_ipv4 = ipmatcher.parse_ipv4(remote_addr)
            if is_ipv4 then
                local data, err = location:search(remote_addr)
                if data then
                    ip_detail["country"] = data["country"]
                    ip_detail["province"] = data["province"]
                    ip_detail["city"] = data["city"]
                    ip_detail["isp"] = data["isp"]
                    ngx.say(json_encode(ip_detail))
                else
                    ngx.say(err)
                end
            else
                local is_ipv6 = ipmatcher.parse_ipv6(remote_addr)
                if is_ipv6 then
                    local data, err = geo.lookup(remote_addr)
                    if data then
                        ip_detail["country"] = data["country"]["names"]["zh-CN"]
                        ip_detail["continent"] = data["continent"]["names"]["zh-CN"]
                        if data["subdivisions"] then
                            local subdivisions = data["subdivisions"][1]["names"]
                            local province_cn = subdivisions["zh-CN"]
                            if province_cn then
                                ip_detail["province"] = province_cn
                            else
                                ip_detail["province"] = subdivisions["en"]
                            end
                        end

                        if data["city"] then
                            local city = data["city"]["names"]
                            local city_cn = city["zh-CN"]
                            if city_cn then
                                ip_detail["city"] = city_cn
                            else
                                ip_detail["city"] = city["en"]
                            end
                        end
                        ngx.say(json_encode(ip_detail))
                    end
                end
            end
        }
    }
}

使用示例

$ curl ip.test.com
180.167.11.11

$ curl ip.test.com/ip
{"ip":"180.167.11.11","country":"中国","province":"上海","city":"上海","isp":"电信"}

$ curl 'ip.test.com/ip?ip=1.1.1.1'
{"isp":"CloudFlare","ip":"1.1.1.1","country":"澳大利亚","province":"0","city":"0"}

$ curl 'ipip.test.com/ip?ip=240b:4000:f10::e3'
{"ip":"240b:4000:f10::e3","country":"新加坡","province":0,"city":0,"isp":0,"continent":"亚洲"}