暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

使用 ip2region 构建私人地址库

生有可恋 2022-12-08
3256

假如让我们自己设计一个IP地址的备注系统,把全网IP地址存到纯文本文件中,这个文件预计会有多大?

全网 IPv4 地址范围为 0.0.0.0 到 255.255.255.255,共计有 4294967295,即 42 亿个地址。如果用文本文件来存IP地址,一行一个。1亿个IP地址大概占用的磁盘空间为1.3GB,42亿个地址大概会占用50G的空间。

这些数据不管放在哪儿,查询效率都是个问题。如果放在数据库中,行数为千万级的表在业务中已经属于大表,要单独拿出来优化。而 ip2region 采用的是IP段的方式来备注IP的属地信息。

ip2region是一个离线IP地址定位库和IP定位数据管理框架,具有10微秒级别的查询效率,通过它自己定义格式的数据库文件xdb来提高查询效率。

它自带的 ip2region.xdb 数据库文件只有11M大小,包含了 0.0.0.0 到 255.255.255.255 全网的 IP 地址属地信息。

它的项目地址为:

  • https://github.com/lionsoul2014/ip2region


使用 git clone 下来后,它提供了 ip2region.xdb 文件和一个数据库文件生成器,以及使用接口。其项目代码的目录结构如下:

    ip2region
    ├── ReadMe.md
    ├── binding
    │   ├── python
    ├── data
    │ ├── global_region.csv
    │ ├── ip.merge.txt
    │ └── ip2region.xdb
    ├── maker
    └── python


    我们先看下如何使用,ip2region 提供了一个交互式测试接口,可以用来交互式查询 IP 属地信息。使用方法为:

      $ cd binding/python/
      $ python ./search_test.py --db=../../data/ip2region.xdb --cache-policy=content
      ip2region xdb searcher test program, cachePolicy: content
      type 'quit' to exit
      ip2region>> 192.168.10.1
      {region: 0|0|0|内网IP|内网IP , took: 0.0 ms}
      ip2region>> 114.114.114.114
      {region: 中国|0|江苏省|南京市|0 , took: 0.0 ms}
      ip2region>> 8.8.8.8
      {region: 美国|0|0|0|Level3 , took: 0.0 ms}
      ip2region>> 202.103.24.68
      {region: 中国|0|湖北省|武汉市|电信 , took: 0.0 ms}
      ip2region>>


      可以看到查询效率都在微秒级,它返回的数据格式为 `国家|区域|省份|城市|ISP`,只有中国的数据绝大部分精确到了城市,其他国家部分数据只能定位到国家,字段中数据为空时用 0 表示。

      除了可以交互式查询,它也支持批量查询,demo 代码可参考以下文章


      ip2region 查询依赖 xdb 数据库文件,它的数据来源主要来自以下三个服务:

      • 淘宝IP地址库

      • GeoIP

      • 纯真IP库


      目前淘宝IP地址库已经发出下线通知,服务截止至2022年3月31日起永久关停服务,不再对外提供API查询。好在 ip2region 把原始数据保存了下来,存放在 data/ip.merge.txt 文件中,共计 683591 个网段。我们可以在这个数据的基础上构建自己的 xdb 数据库文件。

      我们先看下ip.merge.txt数据文件的内容,思考一下基于这个地址段数据能做些什么。

        $ cd ip2region/data
        $ grep 内网 ip.merge.txt

        原始数据格式为 `起始地址|结束地址|国家|区域|省份|城市|ISP` ,我们可以从 ip.merge.txt 中过滤出我们感兴趣的地址段。比如内网地址段,国内地址段,省内地址段。其中这里显示的内网地址段比我们常见的三个地址段要更多,其中加了部分运营商级私有地址段,这个是扩展协议。因为公网地址不足,所以运营商拿出来一部分地址作为NAT地址,这部分原属于公网地址的部分也被纳入到私网地址,只有运营商会使用。

        我们常用的内网地址段为:

        • 10.0.0.0-10.255.255.255

        • 172.16.0.0-172.31.255.255

        • 192.168.0.0-192.168.255.255


        国内地址段:

          $ grep 中国 ip.merge.txt

          有了原始数据,我们看下如何基于原始数据生成 xdb 数据库文件。

            $ cd maker/python/
            $ python main.py gen --src=../../data/ip.merge.txt --dst=./my.xdb

            通过 ip2region 提供的 maker 程序,可以生成自己的 xdb 文件。原始数据是可以维护的,txt 版本的数据文件为 40M,生成 xdb 文件后只有 11M。

            这里需要注意的是自己构造的 ip.merge.txt 文件,地址段必须是连续的,不然会报错:

              $ cat local_ip.txt
              0.0.0.0|0.255.255.255|0|0|0|内网IP|内网IP
              10.0.0.0|10.255.255.255|0|0|0|内网IP|内网IP


              $ python main.py gen --src=./local_ip.txt --dst=./my.xdb
              ERROR - discontinuous data segment: last.eip+1(
              167772160)!=seg.sip(184549375, 10.0.0.0)

              对 maker.py 调试发现每一行的地址必须是连续的,如果出现段之间的跳跃,maker 程序会报错。原始数据文件是从0.0.0.0-255.255.255.255连续的地址段,如果我们只想维护内网地址信息,则需要把各个中断的地址段补全。比如将如下地址段补全:

                0.0.0.0|0.255.255.255|0|0|0|内网IP|内网IP
                10.0.0.0|10.255.255.255|0|0|0|内网IP|内网IP

                补全后的地址段为:

                  0.0.0.0|0.255.255.255|0|0|0|内网IP|内网IP
                  1.0.0.0|9.255.255.255|0|0|0|内网IP|内网IP
                  10.0.0.0|10.255.255.255|0|0|0|内网IP|内网IP

                  补全后程序不再报错:

                    $ python main.py gen --src=./local_ip.txt  --dst=./my.xdb
                    2022-12-07 20:36:49,042-root-99-INFO - try to init the db header ...
                    2022-12-07 20:36:49,042-root-122-INFO - try to load the segments ...
                    2022-12-07 20:36:49,042-root-128-INFO - load segment: `0.0.0.0|0.255.255.255|0|0|0|内网IP|内网IP`
                    2022-12-07 20:36:49,043-root-128-INFO - load segment: `1.0.0.0|9.255.255.255|0|0|0|内网IP|内网IP`
                    2022-12-07 20:36:49,043-root-128-INFO - load segment: `10.0.0.0|10.255.255.255|0|0|0|内网IP|内网IP`
                    2022-12-07 20:36:49,043-root-168-INFO - all segments loaded, length: 3, elapsed: 0.0010013580322265625
                    [...]
                    2022-12-07 20:36:49,729-root-271-INFO - write done, dataBlocks: 1, indexBlocks: (3, 2816), indexPtr: (524567, 563977)
                    2022-12-07 20:36:49,729-root-67-INFO - Done, elapsed: 0m1s

                    生成好的数据文件可以用 bench_test.py 脚本测试数据是否完整:

                      $ cp local_ip.txt my.xdb  d/
                      $ cd ../../binding/python/
                      $ python ./bench_test.py --db=/d/my.xdb --src=/d/local_ip.txt --cache-policy=content
                      Bench finished, {cachePolicy: content, total: 15, took: 0.0 s, cost: 0.0 ms/op}


                      现在的很多程序都在收集我们的位置信息,这个信息可以用来做什么呢?最简单的使用场景就是绑定 IP 和 GPS 经纬度之间的关系。一些大的网站的后台IP地址库就是这么来的。现在的各种 web 服务的后台都是带日志的,以前这些 IP 日志都是没有意义的。但如果IP绑定额外的信息,这些日志数据就变得有意义了。

                      全文完。

                      如果转发本文,文末务必注明:“转自微信公众号:生有可恋”。

                      文章转载自生有可恋,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                      评论