go run . pack -i /tmp/ipv6.txt -o /tmp/ipdb/neo.ipv6.ipdb --loglevel debug
是 bug,不是「IPv6 遍历里混进了真实 IPv4 数据」,而是 并行切分 IPv6 地址空间时,切点落进了 IPv4-mapped IPv6 区间,Find 把它们当 IPv4 查了。
发生了什么
StandardDumper 会把 :: ~ ffff:... 按 CPU 核数切成多段,每段一个 goroutine:
split := ipnet.SplitIPNet(ipStart, ipEnd, readerJobs)
for i := 0; i < len(split)-1; i++ {
wg.Add(1)
go func(ctx context.Context, start, end net.IP) {
// ...
sd := SimpleDumper{
Reader: d.Reader,
ipStart: start,
ipEnd: end,
}
你看到的打印是每个 goroutine 的 [marker, ipEnd],所以顺序是乱的,例如:
Dump ip is :2002:17e9:75c0::, end: 2002:7d80:e700::
Dump ip is :::, end: ::6d7a:c00
Dump ip is :::6d7a:c00, end: 65.246.117.64 ← 问题在这
Dump ip is :186.212.44.0, end: 2001:0:5868:de80::
65.246.117.64、186.212.44.0 不是 txt 里的数据,而是 SplitIPNet 算出来的切分边界。
根因:BaseIPv6 里混了 IPv4-mapped 地址
splitIPNetIPv6 用 BaseIPv6 做参考切点,其中有一批 ::ffff:x.x.x.x 形式:
{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x2, 0xdd, 0x4c, 0x0},
{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x18, 0x67, 0xc0, 0x3},
Go 里这类地址 To4() 会成功,ipdb SDK 就会走 IPv4 查询分支:
if ip := ipv.To4(); ip != nil {
if !db.IsIPv4Support() {
return nil, nil, ErrNoSupportIPv4
}
而你的 txt 加载出的内存库是 纯 IPv6(IPVersion: 2),不支持 IPv4,于是报错 IPv4 not support。
整条链路
ipv6.txt
→ plain.Load:建树(IPv6 only,IPVersion=2)✓
→ StandardDumper:并行扫整个 IPv6 空间
→ SplitIPNet:切点落到 ::ffff:... 段
→ SimpleDumper.Find(65.246.117.64):被当 IPv4 查
→ ipdb SDK:ErrNoSupportIPv4 ✗
小结
| 你的疑问 |
答案 |
| 为啥 pack txt 也走 Find 扫描? |
框架统一走 StandardDumper,没有 txt 直通路径 |
| 为啥 IPv6 扫描里出现 IPv4? |
SplitIPNet 的 BaseIPv6 含 IPv4-mapped 切点,不是 txt 里有 IPv4 |
| 是设计还是 bug? |
对 IPv6-only 库并行 dump 来说,这是 bug |
临时规避
- 单线程:
--reader-jobs 1,避免走 SplitIPNet 多段切分
- 更合理:plain → ipdb 不要全空间扫描,Load 时按行直接写目标 Writer
需要的话我可以帮你改一版:要么修 SplitIPNet 的 IPv6 切分,要么给 plain 输入加直通 pack 路径。
go run . pack -i /tmp/ipv6.txt -o /tmp/ipdb/neo.ipv6.ipdb --loglevel debug
是 bug,不是「IPv6 遍历里混进了真实 IPv4 数据」,而是 并行切分 IPv6 地址空间时,切点落进了 IPv4-mapped IPv6 区间,
Find把它们当 IPv4 查了。发生了什么
StandardDumper会把::~ffff:...按 CPU 核数切成多段,每段一个 goroutine:你看到的打印是每个 goroutine 的
[marker, ipEnd],所以顺序是乱的,例如:65.246.117.64、186.212.44.0不是 txt 里的数据,而是SplitIPNet算出来的切分边界。根因:
BaseIPv6里混了 IPv4-mapped 地址splitIPNetIPv6用BaseIPv6做参考切点,其中有一批::ffff:x.x.x.x形式:{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x2, 0xdd, 0x4c, 0x0}, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x18, 0x67, 0xc0, 0x3},Go 里这类地址
To4()会成功,ipdb SDK 就会走 IPv4 查询分支:而你的 txt 加载出的内存库是 纯 IPv6(
IPVersion: 2),不支持 IPv4,于是报错IPv4 not support。整条链路
小结
StandardDumper,没有 txt 直通路径SplitIPNet的BaseIPv6含 IPv4-mapped 切点,不是 txt 里有 IPv4临时规避
--reader-jobs 1,避免走SplitIPNet多段切分需要的话我可以帮你改一版:要么修
SplitIPNet的 IPv6 切分,要么给 plain 输入加直通 pack 路径。