V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
myqoo
V2EX  ›  程序员

判断 IP 是否为境内,有什么推荐的方案

  •  
  •   myqoo · 2023-04-30 14:00:50 +08:00 · 7651 次点击
    这是一个创建于 610 天前的主题,其中的信息可能已经有所发展或是发生改变。

    要考虑两点,第一是网段的准确性 /实时性,第二是判断性能。

    简单搜了下公开的数据,发现 github 有个 china_ip_list 的项目:

    https://github.com/17mon/china_ip_list/blob/master/china_ip_list.txt

    不过实时性好像不是很高(写着季度更新),不知质量如何。是否还有其他更好的推荐?


    第二个是判断性能。之前用过 nodejs 自带的 BlockList,虽然用起来很简单,但后来发现性能并不好,看了下源码才知道它居然是逐条匹配的,没有任何算法优化。

    之前也有人反馈过这个问题: https://github.com/nodejs/node/issues/46070

    看来目前还是得用 C 写一个 node addon 扩展。

    此外,这个算法只用于查询,并没有增删改,并且 CIDR 的范围也是 2 的次方数,是否可进一步优化?

    43 条回复    2023-05-05 10:22:03 +08:00
    pagxir
        1
    pagxir  
       2023-04-30 14:38:32 +08:00 via Android
    IPv4 的可以用我这个,https://gist.github.com/pagxir/b4552da41207749a7cce6c5512aef692
    二分查找。
    XIU2
        2
    XIU2  
       2023-04-30 14:46:49 +08:00
    @pagxir 问下,
    我以前见到论坛里有个人分享过类似的 PAC 脚本,但和你的写法不一样,哪个效率性能更高一些呢?
    https://gist.github.com/weijarz/a76641504c97f0c3e48e207ec4df7db5
    greatbody
        3
    greatbody  
       2023-04-30 14:52:54 +08:00
    如果你是想屏蔽境内的访问,直接套 Cloudflare ,设置一个禁止访问的区域就可以了。ChatGPT 就是这么做的。
    Xianmua
        4
    Xianmua  
       2023-04-30 14:59:11 +08:00 via iPhone   ❤️ 5
    咳咳,判断能不能访问 google
    NoOneNoBody
        5
    NoOneNoBody  
       2023-04-30 15:03:15 +08:00
    ip 特质就是字符串记录整数,转整数位运算肯定快一点
    cnbatch
        6
    cnbatch  
       2023-04-30 15:06:28 +08:00
    如果单纯想查是否国内,那么 ipip net 就有。
    “宽带症候群”节点那边经常用 ipip 的 BestTrace 工具查中间设备的 IP 归属。有时候稍有偏差,不过都是省市级的偏差(尤其是运营商新增设备时,IP 库记录更新没那么快),放宽到国家范围的话基本都是准确的。

    但可供下载的每日更新的 IP 库并不免费。或者也可以用他们的免费 API 查 IP 。
    star7th
        7
    star7th  
       2023-04-30 15:14:46 +08:00
    如果不考虑实时性的,则很多开源方案。要考虑实时性的,肯定要人家不断付出时间精力成本去维护,基本上不用想着能免费获得。你这属于既要又要。
    开源方案的话,推荐 nodejs 库 geoip-lite ,性能很快的,因为它是预加载所有数据到内存。内存占用一百多 M 吧。
    HawkinsSherpherd
        8
    HawkinsSherpherd  
       2023-04-30 16:22:22 +08:00
    在支持免费 bgp 会话的服务商上搞个 vps 建立 bgp 会话,实时获取全球路由表。
    如果用的是小内存的机型,记得把 bgp 路由灌进系统路由表的功能关掉,具体操作视使用的软件而定。
    用正则表达式过滤出经过特定 AS 的 bgp 路由,然后将输出结果重定向到文件中,再将输出结果格式化。
    lcy630409
        9
    lcy630409  
       2023-04-30 16:38:32 +08:00   ❤️ 1
    不是有 geoip 么?离线版本 快得很
    thevita
        10
    thevita  
       2023-04-30 16:53:03 +08:00
    就是用 ip 库啊,看你需求(准确, 更新, 粒度) 有免费的和收费的企业服务可选
    csrocks
        11
    csrocks  
       2023-04-30 16:59:58 +08:00
    在客户端 curl google.com , 结果提供给服务端😅
    salmon5
        12
    salmon5  
       2023-04-30 17:09:28 +08:00
    @csrocks #11 很多年前 360 浏览器客户端是这么弄的
    leido
        13
    leido  
       2023-04-30 17:31:08 +08:00 via Android
    @salmon5 所以装一个 360 就得被诬陷翻墙
    bug123
        14
    bug123  
       2023-04-30 18:05:13 +08:00
    @Xianmua 谁说境内 IP 不能访问 Google 的
    zictos
        15
    zictos  
       2023-04-30 18:07:58 +08:00
    Xianmua
        16
    Xianmua  
       2023-04-30 18:21:11 +08:00
    @bug123 玩笑,而已。大多数应该访问不了吧,配合其他信息当免费 api 用 虽然不太严谨也不是不行。ip-api#com 这个免费的查询 api 也可用,至于高性能上面就都不满足要求了,看上面几位说的吧
    yolooo
        17
    yolooo  
       2023-04-30 18:23:32 +08:00
    @Xianmua #4 你是懂 IP 的
    VYSE
        18
    VYSE  
       2023-04-30 18:37:05 +08:00   ❤️ 1
    自己 proxy 里写的二叉代码,逻辑可以参考

    def init_chn_list():
    global CHN_IP, KEYS_CHN_IP
    t = requests.get("https://cdn.jsdelivr.net/gh/17mon/china_ip_list@master/china_ip_list.txt", proxies=proxies, stream=True)
    for l in t.iter_lines():
    ip, sub = l.split(b'/')
    ip = ip.decode('ascii')
    ip = struct.unpack("!I", inet_aton(ip))[0]
    ip_end = ip + 2 ** (32 - int(sub))
    CHN_IP.append((ip, ip_end))

    CHN_IP.sort(key=lambda key: key[0])
    INDEX_CHN_IP = [i[0] for i in CHN_IP]
    logger.info('init done')

    def is_chn_ip(ip):
    start, end = CHN_IP[bisect.bisect_right(INDEX_CHN_IP, ip) - 1]
    if end > ip >= start:
    return True
    else:
    return False
    estk
        19
    estk  
       2023-04-30 18:57:30 +08:00 via iPhone
    如果用 cloudflare 的话,header 里就有国家代码
    serafin
        20
    serafin  
       2023-04-30 19:00:39 +08:00
    ipinfo.io
    50k lookups per month.
    Actrace
        21
    Actrace  
       2023-04-30 19:19:44 +08:00
    jsq2627
        22
    jsq2627  
       2023-04-30 21:47:18 +08:00   ❤️ 1
    如果只是想要判断境内,不需要更详细的地理位置,可以用 APNIC 公开的数据,免费,准确,实时
    http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest

    关于性能,可以尝试自己用:
    https://github.com/metowolf/ipdb-packer/blob/master/index.js
    把上面数据打包成 ipdb 格式,用 https://www.npmjs.com/package/ipdb 解析
    kernelpanic
        23
    kernelpanic  
       2023-04-30 21:49:01 +08:00
    ipv4 早就分配完了,已经分给哪个国家的就是哪个国家了,没有实时性一说
    chinafeng
        24
    chinafeng  
       2023-04-30 21:56:03 +08:00
    @kernelpanic #23 IP 地址虽然在 RIR 那几乎分配完毕,但是在二级市场的交易和租用相当活跃
    zelin44913
        25
    zelin44913  
       2023-04-30 22:32:50 +08:00
    http://ip.bczs.net/country/CN
    一直用的这里的数据,实时性挺高的
    realpg
        27
    realpg  
       2023-05-01 00:26:32 +08:00
    世界加钱可及
    JensenQian
        28
    JensenQian  
       2023-05-01 07:22:53 +08:00
    https://ispip.clang.cn/
    这个试下
    每日更新
    sora2blue
        29
    sora2blue  
       2023-05-01 08:26:18 +08:00
    xw
        30
    xw  
       2023-05-01 09:57:38 +08:00 via Android
    alamak76
        31
    alamak76  
       2023-05-01 09:59:05 +08:00
    myqoo
        32
    myqoo  
    OP
       2023-05-01 11:05:43 +08:00
    @pagxir
    @jsq2627 这个不错!有点不明白的是既然 APNIC 都提供数据了,为什么还有 china_ip_list 这样的项目,不知这类项目有什么特殊的地方,还有这么多人用。
    myqoo
        33
    myqoo  
    OP
       2023-05-01 11:10:59 +08:00
    @pagxir 上一条回复 @错了。本来想说你这个代码还可以精简下,把_net_list 变成一个 uint32array + uint8array 看起来可以美观些,初始化和运行性能也可以高一点点。
    Kinnice
        34
    Kinnice  
       2023-05-01 11:33:34 +08:00 via Android
    @myqoo 更准
    Kinnice
        35
    Kinnice  
       2023-05-01 11:35:22 +08:00 via Android
    eg: 202.95.9.1 实际为 hkip ,你看有多少个 ip 库将其识别为内地 ip
    Greatshu
        36
    Greatshu  
       2023-05-01 13:08:00 +08:00   ❤️ 1
    判断能否访问大,纪,元,这个比谷歌更准确
    jsq2627
        37
    jsq2627  
       2023-05-01 13:16:13 +08:00   ❤️ 1
    @myqoo APNIC 只是按照属地原则分配了 IP 所属国家,比如楼上提到的 202.95.9.1 按照 APNIC 是分配到了 SG ,SGNIC 再分配到本地一家 ISP ,但是这家 ISP 在 HK 也有数据中心,把这个 IP 实际用在了 HK 。再比如 Apple 拥有整个 17.0.0.0/8 段,服务器遍布全球各地,但是这段 IP 都不在 APNIC 的分配列表里,因为它都不属于 APNIC 管辖。

    但是如果你的需求只是判断大陆 IP ,用 APNIC 的列表是相对准确的,因为 CNNIC 强制要求各大 ISP 只能广播 CNNIC 分配的 IP 。
    SteveLi77
        38
    SteveLi77  
       2023-05-01 13:30:59 +08:00
    所有套了 cloudflare 的网站都可以在 hostname/cdn-cgi/trace 中找到 loc
    rozbo
        39
    rozbo  
       2023-05-01 16:25:19 +08:00
    套个 cloudflare ,可以直接 block area ,如果还想更细粒度的控制,就开启下 addon header ,不但能获取到国家,城市,连经纬度都可以获取。
    miaomiao888
        40
    miaomiao888  
       2023-05-01 16:30:03 +08:00
    @xw 点进去看到 CF 的中文名原来叫“科赋锐”...
    UnknoownUser
        41
    UnknoownUser  
       2023-05-02 08:43:53 +08:00 via iPhone
    判断 ip 是否在前缀内部可以用 trie tree 搜索
    xzysaber
        42
    xzysaber  
       2023-05-02 10:15:53 +08:00
    不知道实时是需要多实时。
    https://github.com/Loyalsoldier/v2ray-rules-dat ,这个可以参考下。
    cosmain
        43
    cosmain  
       2023-05-05 10:22:03 +08:00
    性能应该是调用 ipset 性能会搞不少吧
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1307 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 43ms · UTC 17:40 · PVG 01:40 · LAX 09:40 · JFK 12:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.