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

364 天前
 myqoo

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

简单搜了下公开的数据,发现 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 的次方数,是否可进一步优化?

6824 次点击
所在节点    程序员
43 条回复
pagxir
364 天前
IPv4 的可以用我这个,https://gist.github.com/pagxir/b4552da41207749a7cce6c5512aef692
二分查找。
XIU2
364 天前
@pagxir 问下,
我以前见到论坛里有个人分享过类似的 PAC 脚本,但和你的写法不一样,哪个效率性能更高一些呢?
https://gist.github.com/weijarz/a76641504c97f0c3e48e207ec4df7db5
greatbody
364 天前
如果你是想屏蔽境内的访问,直接套 Cloudflare ,设置一个禁止访问的区域就可以了。ChatGPT 就是这么做的。
Xianmua
364 天前
咳咳,判断能不能访问 google
NoOneNoBody
364 天前
ip 特质就是字符串记录整数,转整数位运算肯定快一点
cnbatch
364 天前
如果单纯想查是否国内,那么 ipip net 就有。
“宽带症候群”节点那边经常用 ipip 的 BestTrace 工具查中间设备的 IP 归属。有时候稍有偏差,不过都是省市级的偏差(尤其是运营商新增设备时,IP 库记录更新没那么快),放宽到国家范围的话基本都是准确的。

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

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/936578

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX