跳转到内容

IPDB 格式

简介

IPDB 数据库是由 IPIP.net 设计并使用的一种 IP 数据库格式,以体积小、查询效率高、支持多语言等特点而知名。(高老师牛逼~)

格式分析

Terminal window
+--------------------------------+--------------------------------+
| MetaData Length (4byte) | MetaData (Json Format) |
+--------------------------------+--------------------------------+
| Node Chunk (Prefix Tree / Trie) |
+--------------------------------+--------------------------------+
| Data Chunk |
+--------------------------------+--------------------------------+
  • 文件分为三个部分:MetaData、NodeChunk、DataChunk。

MetaData 分析

MetaData 是一个 JSON 对象,包含数据库构建信息和查询所需的元数据。以下是一个示例:

Terminal window
{
"build": 1632971142, // 构建时间
"ip_version": 1, // IP库版本 IPv4:0x1 IPv6:0x2
"languages": {
"CN": 0 // 语言 & 字段偏移量
},
"node_count": 8705098, // Node数量
"total_size": 90028407, // NodeChunk+DataChunk 数据大小
"fields": [ // DataChunk中每组数据的字段
"country_name",
"region_name",
"city_name",
"owner_domain",
"isp_domain",
"latitude",
"longitude",
"timezone",
"utc_offset",
"china_admin_code",
"idd_code",
"country_code",
"continent_code"
]
}

NodeChunk 分析

NodeChunk 由前缀树(字典树)构成。每个 Node 为 8 字节,存储到下一个节点的偏移量。如果偏移量超过节点数,则跳转到 DataChunk,表示找到了结果。

DataChunk 分析

DataChunk 存储 IP 数据库数据。相同的数据仅存储一次,以减少冗余。

Terminal window
+--------------------------------+--------------------------------+--------------------------------+
| Data Length (2byte) | Data Fields(<country>\t<province>\t<city>\t<isp>\t<country>\t<province>) |
+--------------------------------+--------------------------------+--------------------------------+
| Data Length (2byte) | Data Fields(<country>\t<province>\t<city>\t<isp>\t<country>\t<province>) |
+--------------------------------+--------------------------------+--------------------------------+
  • DataChunk 在数据块中,数据分为长度和数据两部分。
  • 数据部分使用 \t 分隔字段,在多语言版本的数据库中使用字段偏移返回不同语言的数据。

查询操作

  • CIDR 地址是一种结合了 IP 地址和子网掩码的网段描述方式,如 10.0.0.1/8 表示一个 8 位子网掩码(255.0.0.0)。CIDR 网段内的所有 IP 在子网掩码部分完全相同。
  • 将 IP 地址视为一个 32位/128位 的二进制字符串,在节点块中使用前缀树从前往后查询,一旦找到 CIDR 匹配,就跳转到数据块返回相应数据。
  • 更多的 CIDR 分组会导致更大的节点数。
  • CIDR 不得相互包含,嵌套的 CIDR(如 10.0.0.1/8 和 10.0.0.1/16)可能会因为先匹配到的原因而阻止进一步匹配。
  • 关于查询过程的详细解释,请参考论文 IPv4 route lookup on Linux

打包流程

  • 构建前缀树,并按照加载顺序将不同的数据集放入数据块。
  • 根据 IPv6 的规范构建前缀树,IPv4 数据需要填充前 96 位的子网数据,即 80 位的 0 和 16 位的 1,对应于 IPv6 的映射地址(::FFFF:)。查询 IPv4 时,这允许快速偏移到 96 位掩码位置开始查询。
  • 理论上,ipdb 格式数据库支持将 IPv4 和 IPv6 数据存储在同一个文件中,但确保 ::FFFF: 的路径上没有其他 CIDR 记录,以保持 IPv4 查询路径畅通(修改查询 SDK 可以更好地支持同时查询 IPv4/IPv6)。