纯真网络IP数据,这个名字在圈子里流传了很多年。可能新手乍一听觉得就是个“某网的数据库下载地址”,但懂行的人看到这个名词,眼睛会亮一下——这是国内老牌的离线IP归属地数据库,做网络运维、日志分析、流量溯源的人,手里基本都留着一份。它不像在线API那样要依赖网络和额度,本地解析毫秒级响应,批处理百万条日志也不心疼。这篇文章我就从纯真IP库的下载、二进制格式解析开始,一路串到怎么在GNS3模拟器里搭两台路由器分析IP数据转发、用Wireshark抓取固定IP的报文并观察ARP协议交互,把整条链路完整拆给你看。
1. 纯真网络IP数据是什么:为什么懂行的人手里都有一个离线IP库
1.1 纯真IP数据库的历史与定位
纯真网络(CZ88.NET)的IP归属地数据库属于离线数据库的“老骨干”。它从很早就开始维护,以二进制.dat文件形式提供,主要包含IP地址段起始、结束地址、地理位置、ISP运营商信息等。它的查询方式和在线接口完全不同:在线接口是每次请求发过去一个IP,服务端返回JSON文本;纯真库则是本地文件,写一个查询程序读文件、二分查找、直接返回归属地字符串。
用生活里的例子打比方:在线IP查询API就像你每次想知道某个人住哪个城市,都打电话问社区服务中心;纯真离线库呢,就像你直接买了一本厚厚的电话黄页放在手边,翻得快,也不用担心对方什么时候下班、要不要收费。所以哪怕现在云计算、大数据概念满天飞,做日志分析和网络排障的人,还是会囤一份离线IP库在本地。
1.2 离线IP库比在线API强在哪
不少人会问:现在有那么多免费在线IP接口,为什么还要折腾本地库?我实际用下来的体感如下:
- 速度:本地纯内存查询微秒级,在线API最少也有几十毫秒网络延迟,批量分析100万条日志时差异是几秒和几十分钟的差距。
- 隐私:日志里的IP就是访问者的“门牌号”,把大量IP发送给第三方接口,等于把自己用户的行踪交给别人,很多公司不允许这么做。离线库查询不出内网,数据完全本地闭环。
- 稳定性:在线接口经常限流、变更参数、甚至突然失效;本地库只要文件在,程序就能一直跑,不受网络波动影响。
- 可集成:离线库可以嵌入到旁路监控系统、防火墙策略模块、自研网管平台中,完全不依赖公网服务。
1.3 典型应用场景
在我过往的项目里,纯真IP库最常见的使用场景有下面几类:
- 日志分析:对Web访问日志、防火墙日志里的源IP做批量归属地解析,快速得出用户地域分布。
- 流量溯源:在网络攻击排查或异常流量分析时,用Wireshark抓到大量来源IP,结合IP库判断这些源IP的归属地、运营商。
- 地域访问控制:配合防火墙或自研网关,对某些地域、某些运营商的IP段做封禁或放行策略。
- GNS3/SDN实验辅助:在模拟网络环境里标注节点IP归属地,方便理解不同网段的报文走向。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 下载更新与格式解析:拿到地址只是开始
2.1 下载地址与更新方式
纯真网络的数据更新,主要有三条路。
- 官方安装包下载:在纯真网络官网下载完整客户端,里面包含最新.dat数据文件,这个方式最稳妥,适合首次获取。
- 更新程序自动更新:纯真网络有一个update.exe类似的更新器,运行它会连接官方更新服务器,拉取最新数据增量合并到本地.dat文件。
- 脚本化更新:有些老手会直接请求纯真网络的更新接口,接口返回一个专门的数据结构体,内部封装了最新数据文件的二进制内容。这个接口返回的不是普通文本,直接落地成.dat文件就行,大多数情况下需要自己控制请求头和二进制写入逻辑。
我个人的建议是:首次下载走官方客户端,日常更新写一个定时任务每周末跑一次更新程序,或者直接调用封装好的Python模块(如qqwry),不要自己手写HTTP轮询逻辑——没必要重复造轮子,而且官方更新协议偶尔会调参,造轮子容易踩坑。
下载完成以后,先做一个基础健康检查:查看.dat文件大小是否在几MB量级,是否包含正常的文件头,用十六进制编辑器打开看一眼能确认文件头不是空的。这一步能避免后续解析程序报错半天,最后发现文件本身下载损坏。
2.2 内部二进制格式原理解读
纯真IP库(.dat)的内部结构,看起来很古老,但设计得相当实用。整个文件,由三大块组成。
- 文件头:固定长度,里面存放索引区的起始偏移和结束偏移。程序读入文件后先解析这两个偏移值,才知道索引区在哪里。
- 索引区:每条索引固定8字节,前4字节是IP段起始地址(转成网络字节序的32位无符号整数),后4字节是记录区偏移量。
- 记录区:每个记录包含一个IP段的起止地址(合计8字节)、指向地理位置字符串的偏移量(3字节)和地理位置字符串本身。
地理位置字符串是GBK编码,不是UTF-8。这是一个经典大坑:很多人自己写解析器,解析出的中文全是乱码,就是因为没有做GBK到UTF-8的转换。另外纯真库对每个IP段的归属地信息来自历史收录,个别条目可能存在地理位置描述不准确,例如政变后国家名称变更等,这属于数据源的固有限制。
2.3 用Python写一个最简解析器
理解了格式,写一个解析器就顺理成章了。这里我给出一个只依赖标准库的Python示例,方便你在不同环境里直接跑起来。
python复制import struct
import socket
def ip_to_int(ip):
# 把点分十进制IP转成32位整数
return struct.unpack('!I', socket.inet_aton(ip))[0]
def int_to_ip(num):
return socket.inet_ntoa(struct.pack('!I', num))
class QQWry:
def __init__(self, filepath):
with open(filepath, 'rb') as f:
data = f.read()
self.data = data
# 读取文件头
self.index_start, self.index_end = struct.unpack('<II', data[0:8])
def lookup(self, ip):
ip_int = ip_to_int(ip)
# 二分查找索引区
low = self.index_start
high = self.index_end - 12 # 每条索引8字节,最后一次取12字节因为记录边界
while low <= high:
mid = (low + high) // 2
# 索引区每8字节一组:起始IP + 记录偏移
mid = mid - (mid - self.index_start) % 8 # 对齐到索引边界
start_ip = struct.unpack('<I', self.data[mid:mid+4])[0]
end_ip = struct.unpack('<I', self.data[mid+4:mid+8])[0]
if ip_int < start_ip:
high = mid - 8
elif ip_int > end_ip:
low = mid + 8
else:
# 读取记录偏移,跳转到记录区
record_offset = struct.unpack('<I', self.data[mid+4:mid+8])[0]
return self._parse_record(record_offset)
return None
def _parse_record(self, offset):
# 记录区开头是8字节的起止IP,然后跟一个4字节地理位置偏移或直接是字符串
area_offset = struct.unpack('<I', self.data[offset+4:offset+8])[0]
# 大多数情况:首字节0x01表示重定向,指向另一条记录
if self.data[area_offset] == 0x01:
area_offset = struct.unpack('<I', self.data[area_offset+1:area_offset+4])[0]
addr = self._read_string(area_offset)
else:
addr = self._read_string(area_offset)
return addr
def _read_string(self, offset):
# 从偏移开始读到0x00结尾,然后GBK解码
end = self.data.find(b'\x00', offset)
return self.data[offset:end].decode('gbk', errors='replace')
if __name__ == '__main__':
db = QQWry('qqwry.dat')
print(db.lookup('39.156.66.10'))
这个代码只处理了基础情况,真实纯真库记录里还有“二级地理位置”的存储逻辑,需要更多判断语句。但核心思想就是:索引二分、跳转读取、GBK解码。你会看到,整个过程没有涉及任何外部API,数据全在一份文件里完成。
3. IP数据到底是怎样在网络中跑起来的:GNS3实验中的转发过程
3.1 TCP/IP模型传输过程速览
很多初学者背过TCP/IP四层模型,但实际操作的时候,一旦看到报文从主机经过路由器穿过网络再到达目标主机,经常会犯迷糊。我把这个过程用寄快递的方式拆了一遍。
应用层:你写好邮件内容,这就是应用层数据。传输层:系统帮你贴上快递单,写上“源端口”和“目的端口”,比如HTTP用的80端口、HTTPS用的443端口。网络层:再套一个外包装,写上“源IP地址”和“目的IP地址”,这是整个网络中最重要的门牌号。数据链路层:到了路由器这个“分拣站”,还要贴上“下一站的收件人姓名”——也就是目标MAC地址。物理层:最终变成电信号或者光信号发出。
这样一个从PC1到PC2的报文,应用层数据在最里面,传输层加头,网络层加头,链路层加头,每一层都只处理跟自己相关的信息,其他信息不关心。GNS3实验能帮你直观看到这个过程:同一份ICMP数据,在PC1网卡上是一个样,在R1上转出去又是一个样。
3.2 IP数据转发与ARP的“问路”机制
IP地址定位的是“最终目的地”,MAC地址定位的是“下一站”。两台设备之间要通信,必须知道下一跳的MAC地址。这时ARP协议就登场了:主机想知道某个IP的MAC地址,就在本地广播一个“谁是这个IP,请告诉我你的MAC”,目标收到后单播回复自己的MAC。
在GNS3环境里,这个现象尤其明显。PC1要访问PC2,两个主机不在同一个网段,所以PC1不会直接ARP解析PC2的MAC,而是把报文交给网关(R1的接口),所以PC1会发出ARP广播请求“网关IP的MAC是谁”。R1收到报文后,查路由表发现目的PC2不在直连网段,走下一跳R2,于是R1又需要ARP解析R2对应接口的MAC。你会发现,IP地址从头到尾没变过,但MAC地址在每一跳都被改写。这一点非常关键,也是抓包分析时的主线。
3.3 用GNS3搭建双路由器实验拓扑
我们直接搭一个最经典的拓扑:两台路由器分别连接一台主机,然后两台路由器互联。本文的场景是“GNS3中两个路由器分别连接主机,然后分析IP数据转发报文与ARP协议”,所以我建议的拓扑是:
text复制PC1 --- R1 --- R2 --- PC2
规划地址如下:
| 设备 | 接口 | IP地址 | 说明 |
|---|---|---|---|
| PC1 | eth0 | 192.168.1.10/24 | 网关指向R1 f0/0 |
| R1 | f0/0 | 192.168.1.1/24 | 连接PC1 |
| R1 | f1/0 | 10.0.12.1/30 | 连接R2 f1/0 |
| R2 | f1/0 | 10.0.12.2/30 | 连接R1 f1/0 |
| R2 | f0/0 | 192.168.2.1/24 | 连接PC2 |
| PC2 | eth0 | 192.168.2.10/24 | 网关指向R2 f0/0 |
在GNS3里,建议使用思科IOS路由器镜像,PC使用VPCS这种轻量级模拟终端会非常方便。VPCS里只需要配置IP和网关,敲命令的速度比真实PC快得多。
R1上的配置大致如下:
text复制interface f0/0
ip address 192.168.1.1 255.255.255.0
no shutdown
interface f1/0
ip address 10.0.12.1 255.255.255.252
no shutdown
ip route 192.168.2.0 255.255.255.0 10.0.12.2
R2上的配置大致如下:
text复制interface f0/0
ip address 192.168.2.1 255.255.255.0
no shutdown
interface f1/0
ip address 10.0.12.2 255.255.255.252
no shutdown
ip route 192.168.1.0 255.255.255.0 10.0.12.1
配完以后在PC1上ping 192.168.2.10,第一次大概率会通,因为静态路由已经把路径指好了。但这个过程中报文到底是怎么转的,ARP请求长什么样,就要交给Wireshark来揭晓。
4. Wireshark抓取固定IP数据:过滤器别再用错
4.1 抓包前的正确姿势
Wireshark抓固定IP数据,最核心的是过滤表达式,很多人上来就敲ip.addr==192.168.1.10,但其实这个表达式匹配的是“源IP或者目的IP为192.168.1.10的所有报文”。大多数场景没问题,但你如果只关心PC1发出的包,或者只关心发送到PC2的包,就得分清ip.src和ip.dst。
我用下来比较实用的过滤写法有这些:
- 只看某个IP作为源或者目的,
ip.addr==192.168.1.10 - 只看某个IP发出的包,
ip.src==192.168.1.10 - 只看发往某个IP的包,
ip.dst==192.168.2.10 - 只看ARP协议,
arp - 只看ARP中某个IP相关的包,
arp.src.proto_ipv4==192.168.1.1 - 组合过滤,
ip.src==192.168.1.10 && icmp
另外一个非常容易踩的坑是选错抓包接口。GNS3里如果你用云设备连接真实网卡,通常要选择对应虚拟网卡(如VMnet、Loopback或GNS3 UDP接口);如果用的是VPCS,Wireshark一般能自动捕获到对应内部接口。抓包前先跑一小段流量,看看Wireshark主界面有没有报文在滚,如果没有,九成是接口选错了。
4.2 完整抓包过程:从ping开始
接下来做一次标准抓包。我在PC1上打开命令行,持续ping PC2的IP:ping 192.168.2.10 -t(Windows持续ping),或者VPCS里直接ping 192.168.2.10。同时在PC1连接R1的那个链路中间开启Wireshark捕获。
抓到的报文大致会分成两类:
- ARP广播请求:PC1第一次发报文给网关之前,会先广播“192.168.1.1的MAC地址是多少”。
- ICMP报文:ARP解析完成以后,ICMP Echo Request开始发出。此时的以太网帧头里,目的MAC就是R1 f0/0的MAC,源MAC是PC1的MAC;IP头里源IP是192.168.1.10,目的IP是192.168.2.10。
接着把Wireshark换到R1和R2之间的链路上再抓一轮,你会发现ICMP报文的目的MAC变成了R2 f1/0的MAC,但IP层的源IP和目的IP和之前一模一样。这就是IP数据转发最直观的证据:三层地址端到端不变,二层地址逐跳修改。
这个实验最有意思的地方,是把“路由”这个抽象概念变成了可看见的帧:R1并没有修改IP头,它只做了一件事——拆掉旧帧头,重新封装新帧头,然后按路由表选择合适的接口发出去。
4.3 报文逐层拆解:ARP与IP转发观察点
在Wireshark里点开任意一个ICMP Echo Request报文,从上到下你能看到这些关键内容:
- Frame:物理层信息,包含帧长度、接口信息。
- Ethernet II:二层头,源MAC、目的MAC、上层协议类型(0x0800表示IPv4)。
- Internet Protocol Version 4:三层头,源IP、目的IP、TTL、协议字段(1表示ICMP,6表示TCP,17表示UDP)。
- Internet Control Message Protocol:四层数据,包含类型(8代表Echo Request,0代表Echo Reply)、标识符、序号。
对比PC1侧和R1-R2链路侧抓到的同一组ICMP,我列了下面这个表:
| 观察点 | 源MAC | 目的MAC | 源IP | 目的IP |
|---|---|---|---|---|
| PC1到R1链路 | PC1 | R1 f0/0 | 192.168.1.10 | 192.168.2.10 |
| R1到R2链路 | R1 f1/0 | R2 f1/0 | 192.168.1.10 | 192.168.2.10 |
| R2到PC2链路 | R2 f0/0 | PC2 | 192.168.1.10 | 192.168.2.10 |
MAC地址三跳都不同,IP地址三跳都不变。你在Wireshark里配合“着色规则”把ARP染成黄色、ICMP染成绿色,一眼就能看出ARP广播请求和ICMP数据轮番出现的过程。
4.4 抓包数据配合纯真IP库辅助分析
搞定了报文观察以后,为什么还要结合纯真网络IP库?因为在实际场景中,你抓到的往往不是自己模拟器的测试流量,而是办公网、服务器上的一大堆访问IP。比如Wireshark捕获了一批外部扫描IP,你不知道这些IP是哪里的、属于什么运营商,这时候纯真库就能帮你批量做归属地标注。
我之前写过一个简单脚本,从Wireshark导出的CSV里提取源IP列,然后调用本文那个QQWry解析器,一条命令就输出每个IP对应的省份、城市、运营商。这样做的好处是,分析日志“这些攻击来源主要集中在哪里”就变得很快,不用一个个去查在线库。这也是我始终保留离线IP库的原因:线上抓包+线下分类,整个流程完全不依赖公网。
5. 常见问题与排查技巧实录
5.1 IP库使用中的典型问题
下载文件乱码、解析报错,是本地库绕不开的坑。
- IP库文件损坏:下载工具断点续传可能导致文件不完整,务必用校验工具对比MD5,或者重新用官方客户端下载。纯真库文件如果文件头读出的索引偏移值明显异常,基本上就是文件坏了。
- 中文乱码:解析程序只解码成GBK,或者错误地按UTF-8解码,都会乱码。编码转换是绕不过去的一步,建议在存储和展示阶段统一转成UTF-8。
- 地域信息不准确:离线库是定期更新的快照,不是实时更新的在线数据库,一些新划分的运营商、新建成的机房,数据可能滞后。解决办法是保持每周更新。
5.2 GNS3与Wireshark排障速查
我在实验中最常遇到的问题是抓不到包和ping不通,下面这些排查步骤基本能解决九成的问题:
- 接口没有进入Wireshark:在GNS3里,点击拓扑中的链路节点,选择“Start Capturing”而不是自己单独开Wireshark去选一个网卡。GNS3生成的pcap文件会直接关联到Wireshark打开。
- 双路由器之间不通:先检查两台路由器互联接口的IP是否同网段,再看路由表里有没有对应回程路由。我在R1上指了去192.168.2.0的路由,但R2如果忘了指回192.168.1.0的路由,PC1 ping PC2就会发出去,但回包丢了。
- 第一次ping很慢,后续很快:这是ARP缓存在起作用。第一次要广播解析MAC地址,所以慢;第二次缓存在了,不需要ARP,速度就起来了,这是正常现象。
- 抓到的ARP包很多,但看不到数据包:很可能是路由有问题,主机一直在尝试解析网关MAC,或者网关MAC解析成功但路由不可达。先在路由器上用
show ip route确认路由表。
5.3 几个提升效率的小工具
用纯真IP库和Wireshark配合的时间长了,我给自己整理了下面这套小动作,非常管用:
- 把解析器封装成命令行工具,支持
query --file qqwry.dat --ip 1.2.3.4这种形式,批量扫描日志时就方便了。 - 在Wireshark里保存一组自定义过滤器,比如
ip.src==192.168.0.0/16 || ip.dst==192.168.0.0/16,过滤内网流量,只看公网来源。 - 在GNS3里做完拓扑,保存一份端口与IP对应表,方便复现实验。
- 记录每一次更新的纯真库文件哈希值,防止被中间人篡改。
| 问题现象 | 可能原因 | 处理办法 |
|---|---|---|
| 纯真库解析乱码 | 编码未从GBK转成UTF-8 | 统一在读取字符串后decode('gbk') |
| 抓包接口无流量 | GNS3中未正确关联Wireshark pcap | 右键链路节点点Start Capturing |
| ping不同PC2 | R2缺少回程路由 | 在R2添加ip route 192.168.1.0/24指向R1 |
| 大量ARP但无业务报文 | 后路由指向错误或ACL拦截 | 检查路由表与ACL配置 |
| 报文到了R2但PC2不回复 | PC2网关配置错误 | 确认PC2的默认网关为192.168.2.1 |
我个人在实际操作中的体会是:别小看一个离线IP库的价值。哪怕在线API做得再方便,真要分析批量日志、做地域标注的时候,本地库带来的流畅感和掌控感是无法替代的。同时,抓包这件事,最忌讳的就是盯着过滤器空想,不如动手搭一套GNS3拓扑,把一个ping包从PC1送到PC2,亲眼看看ARP广播、IP报文转发、MAC地址逐跳改写的过程,你会对整个网络模型有更通透的认识。最后再分享一个经验:这套玩法还可以继续扩展,比如把纯真IP库的解析结果直接导入到ELK日志平台里做地域可视化,或者写一个定期更新脚本自动拉取最新数据入库。真正把这些工具串成流水线以后,你会发现做网络排障和日志分析,少了很多手工查来查去的烦恼。
