cloud-ip-crawler

July 12, 2026 · View on GitHub

一条命令,把主流云厂商、大机房和两千多家托管商的 IP 段抓下来,汇总成一个 SQLite 数据库,用来判断某个 IP 是不是机房 IP。

CI Daily dataset License: MIT

English: README.en.md

为什么做这个

判断一个 IP 是机房的还是家庭宽带的,是很多事情的第一步。

数据分三层,置信度从高到低:

  1. 官方文件(AWS、GCP、Azure、Cloudflare、Fastly 等 11 家)。各家自己发布的服务网段清单,最准,但格式各不相同:AWS 给 JSON,DigitalOcean 给 CSV,Linode 和 Vultr 用 Geofeed,Bunny CDN 干脆给一串单个 IP,Azure 则藏在一个每周换网址的下载页后面。
  2. 命名 ASN(Hetzner、OVH、Contabo、Akamai、Rackspace、阿里云、腾讯云、华为云 等 25 家)。它们不发官方清单,改从各自的 ASN 取「当前对外宣告的前缀」。
  3. hosting 兜底层。一家一家列举托管商永远列不完,这层换思路:对全球 BGP 表里每个 ASN 的名称做关键词匹配(HOSTING / VPS / CLOUD / SERVER / DATACENTER / IDC…),把两千多个「名字里就写着自己是托管商」的 ASN 一次性收进来。大厂骨干 AS(AS16509 AMAZON-02、AS13335 CLOUDFLARENET 等)也在这层显式收录——官方清单只列「对外服务的网段」,1.1.1.18.8.8.8 这类著名漏网之鱼就靠这层兜住。

第 2、3 层共用 iptoasn.com 的全量 BGP 表(一个 6.8 MB 的文件,每日更新,源头是 RouteViews),一次下载覆盖全部,不用逐 ASN 打接口。

纯 Go,不需要 CGO,一个二进制文件跑完就得到一个 25 MB 的 SQLite 数据库,IPv4、IPv6 都有。

快速开始

不想自己跑,直接下载每天自动构建的数据库(SQLite / CSV / MMDB 三种格式):

curl -LO https://github.com/harrisonwang/cloud-ip-crawler/releases/download/dataset-latest/cloud-ip.db.gz
gunzip cloud-ip.db.gz

# nginx / HAProxy 用户直接拿 MMDB
curl -LO https://github.com/harrisonwang/cloud-ip-crawler/releases/download/dataset-latest/cloud-ip.mmdb.gz
gunzip cloud-ip.mmdb.gz

MMDB 配 nginx 的 geoip2 模块,三行就能拿到判定结果:

geoip2 /etc/nginx/cloud-ip.mmdb {
    $cloud_provider provider;   # 非空即机房 IP,值形如 aws / hetzner / hosting
    $cloud_tier     tier;       # official / asn / hosting,置信度从高到低
}

自己跑:

go install github.com/harrisonwang/cloud-ip-crawler/cmd/cloud-ip-crawler@latest
cloud-ip-crawler --db cloud-ip.db

数据库文件不存在会自动建好。全量抓一次大约 30 秒,Azure 占了大半时间。

查一个 IP 是谁的,不用写 SQL:

$ cloud-ip-crawler lookup 1.1.1.1
hosting  1.1.1.0/24  region=US  service=AS13335 CLOUDFLARENET

$ cloud-ip-crawler lookup 52.94.76.10
aws  52.94.76.0/22  region=us-west-2  service=AMAZON
hosting  52.94.72.0/21  region=US  service=AS16509 AMAZON-02

命中退出码为 0,未命中为 1,脚本里可以直接当判断用。同一个 IP 可能列出多条归属(官方清单一条 + hosting 兜底层一条),置信度取前者。

用法

cloud-ip-crawler [flags]           抓取数据
cloud-ip-crawler lookup <ip>       查询一个 IP 的归属
cloud-ip-crawler export [flags]    导出 MMDB(--out cloud-ip.mmdb)

  --db string          SQLite 文件路径(默认 cloud-ip.db,抓取时不存在则自动创建)
  --providers string   逗号分隔的厂商,或 all(默认 all)
  --dry-run            只抓取并打印样例,不写数据库
  --version            打印版本

MMDB 每个 IP 只存置信度最高的一条归属(official > asn > hosting,tier 字段标明来源层);要看全部归属用 SQLite + lookup

# 只更新 AWS 和 GCP,其它厂商的数据原样保留
cloud-ip-crawler --providers=aws,gcp

# 先看看能抓到什么,不落库
cloud-ip-crawler --providers=cloudflare --dry-run

# 不想要启发式兜底层,只要点名的厂商
cloud-ip-crawler --providers=aws,gcp,azure,cloudflare,oracle,digitalocean,linode,vultr,fastly,bunny,zscaler,hetzner,ovh,contabo,leaseweb,gcore,scaleway,netcup,softlayer,buyvm,hosthatch,alibaba,tencent

每家厂商的数据在一个事务里先删后插、整体替换,所以厂商下架的网段不会留在库里。

只要有一个数据源抓失败,程序就以非零状态退出。每天的自动构建靠这个判断要不要发布——宁可今天不更新,也不发一份缺了 Azure 的库。

数据源

都是公开来源,不需要任何 API key。

一、各家自己发布的官方地址

厂商数据源格式
AWSip-ranges.amazonaws.com/ip-ranges.jsonJSON
GCPgstatic.com/ipranges/cloud.jsonJSON
AzureMicrosoft 下载中心JSON
Cloudflarecloudflare.com/ips-v4纯文本
Oracledocs.oracle.com/.../public_ip_ranges.jsonJSON
DigitalOceandigitalocean.com/geo/google.csvCSV
Linodegeoip.linode.comGeofeed
Vultrgeofeed.constant.comGeofeed
Fastlyapi.fastly.com/public-ip-listJSON
Bunny CDNbunnycdn.com/api/system/edgeserverlistJSON(单个 IP 列表)
Zscalerconfig.zscaler.com/api/<cloud>/cenr/jsonJSON

二、命名 ASN 的大机房 / VPS 商家

这些厂商不发官方 IP 文件,改从它们的 ASN 取「当前对外宣告的前缀」。ASN 清单见 internal/crawler/asn.go,每个号都用 RIPEstat 的 as-overview 逐个核对过 holder。

厂商ASN
Hetzner24940, 213230, 212317
OVH(含 Kimsufi / SoYouStart 品牌)16276
Contabo51167
Leaseweb60781, 30633, 7203, 19148, 396190
G-Core199524
Scaleway12876
netcup197540
IBM SoftLayer36351
Frantech / BuyVM53667
HostHatch63473
阿里云45102, 37963
腾讯云132203, 45090
华为云136907, 55990
Akamai(含原 Linode 骨干)20940, 16625, 63949
Rackspace27357, 33070, 12200, 19994
GoDaddy26496
Namecheap22612
M2479009
Selectel49505
Sakura Internet9370, 7684
Fly.io40509
DataCamp / CDN7760068
Kamatera36007
Aeza210644
Timeweb9123

留意语义差别:ASN 拿到的是「该 AS 宣告的所有前缀」,比官方服务清单——可能含厂商自用甚至客户自带(BYOIP)网段。对「判断是不是机房 IP」这个目标,宁可全一点反而合适。

三、hosting 兜底层(启发式)

对 iptoasn 全量表里每个 ASN 的名称做关键词匹配(HOSTING / VPS / VDS / CLOUD / SERVER / DATACENTER / DEDICATED / COLOCATION / IDC),两千多个托管商 ASN 一次性收进来,provider 统一记 hostingservice 记「AS 号 + 名称」便于溯源。中国电信 / 移动的 IDC 分支(CHINANET-IDC-BJ 这类)也会被正确抓到。

大厂骨干 AS 关键词抓不到(AMAZON-02 里没有关键词),在 internal/crawler/iptoasn.go 里显式收录:AS16509 / AS14618(Amazon)、AS8075(Microsoft)、AS15169 / AS396982(Google)、AS13335(Cloudflare)、AS31898(Oracle)、AS14061(DigitalOcean)、AS63949(Linode/Akamai)、AS20473(Vultr)、AS54113(Fastly),同样逐个核对过 holder。

这层是启发式,置信度低于前两层:有少量误报(名字里带 VPS/CLOUD 的小 ISP,实测 2452 个 ASN 里有 3 个可疑),也有漏报(用创始人名字命名、名字里不带行业词的机房)。要纯净数据就 --providers 里不选 hosting

抓一次的量(2026 年 7 月实测):

                 v4     v6
hosting       47632  21801
azure         43310  16067
akamai         6365  12372
aws            7750   2899
linode         5313     98
m247           2584    400
alibaba        1127    280
digitalocean   1078    148
leaseweb        636    555
oracle         1089      0
gcp             991     48
bunny           623    355
ovh             847     69
tencent         827     85
softlayer       733     72
zscaler         572    105
selectel        550     20
huawei          415    113
gcore           445     53
vultr           436     71
timeweb         354     84
godaddy         323     17
rackspace       252      4
contabo         250      2
datacamp        184     33
aeza            177     38
netcup          129     12
hetzner         126      7
scaleway         84     27
kamatera         81     18
namecheap        52     34
hosthatch        75     12
buyvm            25     61
sakura           75      3
flyio            34     39
cloudflare       15      7
fastly           19      2
──────────────────────────
共 181589 条(其中 v6 56011),29 MB,全量抓一次约 27 秒

Azure 的原始数据里有三万多条重复网段(同一个 CIDR 挂在好几个 service / region 标签下),入库时按 (provider, cidr) 去重,只留一条。Zscaler 也一样——同一个节点网段会在几十个城市、几个 cloud 下反复出现,抓到的 3282 条去重后只剩 572 条。ASN 路线的条数看起来比别处少(Hetzner 只有 126 条),是因为 iptoasn 把相邻的同 ASN 网段聚合过,覆盖的地址总量不变。

上游数据不能全信:Vultr 的 geofeed 里混着三个 RFC 5737 测试网段(192.0.2.0/24 等)。特殊用途网段(私网、TEST-NET、组播……)在入库前统一丢弃。

数据表和查询

CREATE TABLE cloud_ip_ranges (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    provider   VARCHAR(100) NOT NULL,   -- aws / gcp / azure / ...
    cidr       VARCHAR(50)  NOT NULL,   -- 52.94.76.0/22
    ip_start   BLOB NOT NULL,           -- 定长存储,可以直接比大小
    ip_end     BLOB NOT NULL,
    region     VARCHAR(100),
    service    VARCHAR(100),
    ip_version TINYINT DEFAULT 4,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(provider, cidr)
);

ip_startip_end 按定长存,所以判断一个 IP 在不在某个网段里,就是一次走索引的范围比较:

import sqlite3, ipaddress

db = sqlite3.connect("cloud-ip.db")
key = ipaddress.ip_address("52.94.76.10").packed

row = db.execute(
    "SELECT provider, cidr FROM cloud_ip_ranges "
    "WHERE ip_version = 4 AND ip_start <= ? AND ip_end >= ? LIMIT 1",
    (key, key),
).fetchone()

print(row)   # ('aws', '52.94.76.0/22')

它能告诉你什么,不能告诉你什么

这一节比上面所有内容都重要。

查到了,看 provider 判断置信度:

  • 命中官方文件厂商awsgcp…):厂商自己说这网段是它的,最准,还带 region / service 标签,直接用。
  • 命中命名 ASN 厂商hetznerovh…):BGP 表说这网段是它宣告的,很准,但可能含厂商自用或客户自带的 IP。
  • 只命中 hosting:一个名字像托管商的 ASN 宣告了它。作为「机房 IP」信号足够强,但 ASN 归类是启发式的,当厂商归属用之前先看看 service 里的 AS 名称。

以前官方清单的著名漏网之鱼现在能兜住了:1.1.1.1(Cloudflare 公共 DNS,不在 ips-v4 里)和 8.8.8.8(Google 公共 DNS)都能从 hosting 层查到归属。

查不到,不等于它不是机房 IP,但概率已经不大了。剩下的漏网主要是:名字里不带行业词的小机房(用创始人名字命名的那种)、企业自建机房、以及躲在住宅代理后面的流量——最后这类本来就不该由 IP 段清单来解决。

v4、v6 都收。 各家 v6 覆盖见上面的表,唯一的空缺是 Oracle——它的官方文件里就没有 v6。查询时按 ip_version 区分:v4 的 key 是 4 字节,v6 是 16 字节,lookup 子命令和 MMDB 对两者一视同仁。

后续计划

欢迎 PR,尤其是前两项:

  • 支持 IPv6:v4 / v6 都收,Oracle(官方文件没有 v6)是唯一的空缺。
  • 打磨 hosting 关键词:误报 / 漏报清单欢迎提 issue,关键词和显式收录 / 排除清单都在 iptoasn.go,改一行的事。
  • 更多命名厂商:往 asn.go 的清单里加一行就行,核对 holder 后提 PR。注意有些牌子没有自有 ASN:Kimsufi / SoYouStart 是 OVH 品牌(同一批 ASN),RackNerd 的 IP 挂在 ColoCrossing(AS36352)名下宣告,hosting 层已覆盖,无法单独打标签。
  • 导出成 MMDBexport 子命令,每日 Release 里有现成的 cloud-ip.mmdb.gz
  • 导出成 JSON。

它的来历

原本是 DetectRadar 里的一个组件,用来识别机房 IP。DetectRadar 是个网页工具,打开就能看到自己的浏览器有没有在泄露真实 IP,免费、不用注册。

许可证

MIT