指南

在日志中区分 IPv4 和 IPv6 访客

像 203.0.113.42 这样的地址和像 2001:db8::1 这样的地址看起来明显不同,但一旦这些地址埋在日志文件或数据库列中,假定只有一种格式的脚本就会悄无声息地错误处理另一种格式。

读取 version 字段

/v1/ip 端点在每个响应中都会返回 version 字段,值为 4 或 6,与其余位置数据一起返回。您无需自己解析地址字符串来判断它属于哪个地址族。

GET /v1/ip?ip=2001:db8::1
{
  "status": "ok",
  "ip": "2001:db8::1",
  "version": 6,
  "found": true,
  "country": "Canada",
  "country_code": "CA",
  "region": "Ontario",
  "city": "Toronto",
  "postcode": "M5H",
  "lat": 43.6511,
  "lon": -79.3808,
  "timezone": "America/Toronto",
  "asn": 4321,
  "org": "Example ISP"
}

为什么这种区分对配额很重要

免费配额按网络计算,而每个地址族对网络的定义不同:同属一个 /24 的所有 IPv4 地址共享一份配额,同属一个 /48 的所有 IPv6 地址共享一份配额。一个分配了大地址块的 IPv6 客户,在您的日志中可能看起来像许多不同的地址,而实际上都位于同一份共享配额之内。了解版本有助于您按正确类型的网络边界对日志条目进行分组,而不是把每个不同的地址字符串都视为互不相关。

一个会出问题的具体案例

一位家庭网络同时支持两种地址族的访客,可能在两次访问中以两个看似无关的地址出现在您的日志中,一个是 IPv4,一个是 IPv6,取决于其设备当天碰巧使用了哪一个。如果简单处理,这看起来就像两位不同的访客。结合版本和会话 Cookie 等稳定标识符进行分组,而不是仅按原始地址分组,可以避免虚增访客数量,或把同一位客户的历史拆分到两个档案中。

实用的日志处理

在原始日志之上编写您自己的分析或滥用检测时,请先根据 version 字段分支,再尝试计算网络前缀,因为把 /24 掩码用于 IPv6 地址毫无意义,把 /48 掩码用于 IPv4 地址同样毫无意义。请把版本与地址本身一起存储,而不是每次读回日志时都通过字符串解析重新推导。

值得避免的错误

把一个为 IPv4 点分表示法编写的正则表达式,应用到同时包含 IPv6 地址的列上,是日志行被悄悄丢弃或错误分类的一个来源。请明确地用两种格式测试所有地址解析代码,包括 IPv6 地址常用的双冒号缩写表示法,而不是假设一种模式就能涵盖两个地址族。

检查的费用

以这种方式查询版本,每检查一个地址计一次请求,与其他任何 IP 查询相同。如果您要审查一个大型日志文件,请通过批量 POST 提交地址,而不是每行发送一个请求,这样每个条目的费用不变,调用次数却少得多。

把 IPv4 和 IPv6 当作真正独立的地址族,而不只是长度不同的字符串,可以避免一类只有在 IPv6 流量占到访客相当比例后才会出现的缺陷。IPv6 查询文档完整介绍了该端点。