lua-resty-ip2region-xdb

ip2region v2.x/v3.x XDB searcher implemented via LuaJIT FFI

$ opm get Appla/lua-resty-ip2region-xdb

lua-resty-ip2region-xdb

LuaJIT FFI based ip2region xdb reader for OpenResty and plain LuaJIT.

This project reads ip2region xdb files directly from memory and supports:

  • IPv4 xdb databases

  • IPv6 xdb databases

  • OpenResty init/init_worker loading

  • low-allocation lookup paths via custom parsers

Requirements

  • LuaJIT

  • FFI support

  • bit

  • table.new

This library is intended for OpenResty, but it can also run in plain LuaJIT.

Installation

Place the module under Lua's package path, for example:

    lib/resty/ip2region_xdb.lua
    lib/resty/ip2region_xdb_ipv6.lua

Then require it as:

    local ip2region = require "resty.ip2region_xdb"

Quick Start

    local ip2region = require "resty.ip2region_xdb"
    
    local db = ip2region.new({
        db_path = "/path/to/ip2region.xdb",
    })
    
    local info, err = db:lookup("8.8.8.8")
    if not info then
        ngx.say("lookup failed: ", err)
        return
    end
    
    ngx.say(info.country)
    ngx.say(info.region)
    ngx.say(info.province)
    ngx.say(info.city)
    ngx.say(info.isp)

OpenResty Usage

The xdb file should be loaded during init_by_lua* or init_worker_by_lua*.

    init_worker_by_lua_block {
        local ip2region = require "resty.ip2region_xdb"
    
        package.loaded.my_ip2region = ip2region.new({
            db_path = "/path/to/ip2region.xdb",
        })
    }

Then use the object in request handling:

    local db = package.loaded.my_ip2region
    local info, err = db:lookup("1.1.1.1")

Constructor

    local db = ip2region.new({
        db_path = "/path/to/file.xdb",
        parser_fn = optional_parser_fn,
    })

Options:

  • db_path: required, xdb file path

  • parser_fn: optional default parser used by lookup_and_parse*

Behavior:

  • xdb file content is cached by db_path inside the worker process

  • the module detects IPv4 vs IPv6 from xdb metadata

  • db.meta exposes parsed header metadata

Return Formats

Most lookup methods accept an optional ct argument controlling the return shape.

ct == nil

Returns a table:

    local info = db:lookup("8.8.8.8")
    -- {
    --   country = "...",
    --   region = "...",
    --   province = "...",
    --   city = "...",
    --   isp = "...",
    -- }

ct == true

Returns multiple values:

    local country, province, city, isp, region = db:lookup("8.8.8.8", true)

ct == 1..5

Returns a single field:

    local city = db:lookup("8.8.8.8", db.IDX_CITY)

other values

Returns the raw region string:

    local raw = db:lookup("8.8.8.8", false)

API

Common Methods

db:lookup(ip, ct?, dst_tab?)

Lookup by text IP string.

  • IPv4 database: dotted IPv4 string

  • IPv6 database: text IPv6 string

db:search_ip(ip, ct?, dst_tab?)

Alias of lookup.

db:lookup_city(ip)

Convenience wrapper returning the city field.

db:search_binary_ip(ip, ct?, dst_tab?)

Lookup by binary IP input.

  • IPv4 database:

    • number uint32 IP

    • 4-byte Lua string

  • IPv6 database:

    • 16-byte Lua string

db:set_parser(parser_fn)

Sets the instance parser used by lookup_and_parse*.

db:lookup_and_parse(ip, parser_fn?)

Performs lookup using text IP input and passes (ptr, len) or (nil, err) into parser_fn.

db:lookup_and_parse_binary(ip, parser_fn?)

Same as above, but for binary IP input.

db:ip_info_contains(ip, nds, ...)

Checks whether the region payload contains any needle.

  • ip: text IP string

  • nds: string or array of strings

db:binary_ip_info_contains(ip, nds, ...)

Same as above, but for binary IP input.

IPv6 Aliases

For IPv6 databases, these aliases are also available:

  • lookup_ipv6

  • search_ipv6

  • lookup_city_ipv6

  • search_binary_ipv6

  • ipv6_info_contains

  • binary_ipv6_info_contains

  • lookup_and_parse_ipv6

  • lookup_and_parse_binary_ipv6

Parser Helpers

ip2region.forward_ptr

Built-in parser helper returning the raw (ptr, len) pair:

    local ip2region = require "resty.ip2region_xdb"
    
    local db = ip2region.new({
        db_path = "/path/to/ip2region.xdb",
        parser_fn = ip2region.forward_ptr,
    })

This is useful when you want to avoid building Lua strings on the hot path.

Advanced Helpers

db.parse_ip(ip)

Current instance IP parser.

  • IPv4 database: text IPv4 to uint32

  • IPv6 database: text IPv6 to 16-byte cdata buffer

db.parse_bin_ip(ip)

Current instance binary IP parser.

  • IPv4 database: 4-byte string to uint32

  • IPv6 database: 16-byte string to 16-byte cdata buffer

db:update_idx(name, value)

Advanced override for field indexes on the current instance.

Supported names:

  • IDX_COUNTRY

  • IDX_REGION

  • IDX_PROVINCE

  • IDX_CITY

  • IDX_ISP

  • IDX_COUNTRY_CODE

This is mainly useful when adapting non-standard region field layouts.

Version Notes

The library supports xdb v2 and v3 style metadata.

Default public indexes are:

  • IDX_COUNTRY = 1

  • IDX_REGION = 2

  • IDX_PROVINCE = 3

  • IDX_CITY = 4

  • IDX_ISP = 5

For xdb version 3, the instance remaps indexes after loading:

  • IDX_COUNTRY = 1

  • IDX_REGION = 2

  • IDX_PROVINCE = 2

  • IDX_CITY = 3

  • IDX_ISP = 4

  • IDX_COUNTRY_CODE = 5

When writing application code, prefer using instance fields such as db.IDX_CITY instead of hard-coded numbers.

Error Handling

Most methods return:

  • success: result

  • failure: nil, err

Common errors:

  • invalid ip

  • ip must be a string

  • ip must be a string(16)

  • needle must not be empty

  • not found

  • xdb file too small or corrupted

Notes

  • In OpenResty, file loading is restricted to init and init_worker phases.

  • xdb content is cached by file path per worker process.

  • Big-endian compatibility is handled in guarded branches, but little-endian Linux is the primary target.

License

Apache License 2.0.

Authors

Appla (@Appla)

License

apache2

Dependencies

luajit

Versions