问一行 VPN 数据集代表什么,答案会越来越多:一家公司、一个监听者、一个公开出口地址、一个可达性结果。每一种都成立,而把它们不加标注地混在一起,会得出一个听起来精确、却毫无意义的合计。单位是一个设计决策,必须在第一次计数之前定下来。已发表的 VPN 统计中大部分混乱,都源于跳过了这一步。

一行是一个主张,不是一个东西

每一行都在主张世界的某种情况,而这个主张有一个主体。正是给主体命名,才使这一行能与另一行相比。

服务商行主张某组织提供一项服务。端点行主张某个地址和端口在讲某种协议。出口行主张流量在某个时刻从某个地址离开。测量行主张某处的探针观察到一个结果。四个主体、四套模式,而把它们不加区分地混在一起,这样的数据集根本无法汇总。

区分项是模式中最便宜的一部分,也是最常被省略的一部分。

先定单位,再作计数

选择能回答你真正问题的单位。数端点回答的是公布了多少监听者;数服务商回答的是涉及多少组织;数出口地址回答的是存在多少个表面上不同的来源。

这些数字不能互换,差距很大。一家服务商可以运营数千个地址,而一个地址可以承载面向不同服务的多个协议监听者。因此地址数既不是服务商数的上界,也不是下界。每次说数字时,都要在同一句话里说明单位。没有单位的数字,是带小数点的意见。

UnitThe row assertsWhat a count of it means
ProviderAn organisation offers a serviceHow many operators appear
EndpointAn address and port speak a protocolHow many listeners were advertised
Exit addressTraffic left from an addressHow many apparent origins exist
ObservationA probe saw a resultHow many tests ran, not how many servers

公开目录提供的是该服务中已公布的参与者。它不是全世界每一处商业、组织和私人部署的清单,把它当作那样的清单,会让每一项派生统计都虚高。

来源属于模式的一部分

没有来源的行无法复核。要记录来源记录、带时区的采集时间、观测方法,以及最近一次出现的状态。

把公布的属性和观测到的属性分开,因为它们的权重不同。目录里的国家标签是公布的主张,不是服务器物理位置的证明。IP 分配标识的是一个网络段,而不是段内的每个租户,也不是其上某个应用的当前运营者。两列加一条备注,永远胜过一个合并字段。

{"endpoint": "203.0.113.10:1194/udp", "unit": "endpoint", "advertised_country": "NL",
 "observed_at": "2026-11-03T02:15:00Z", "method": "udp_probe", "last_seen": "2026-11-03"}

一行 JSON 就让模式变得具体,也比一段描述更好讨论。注意时间戳带时区,而方法是写明而不是隐含的。

按问题去重

重复取决于单位。同一地址上的两个协议监听者是一对端点、两项服务,悄悄把它们合成一个就会改变计数。

在问题所问的层级上去重,并记录每一保留行由多少原始行合并而来。这个比例本身就是一项发现,因为大幅合并通常意味着来源按监听者逐条发布。运营大量地址的服务商会呈现相反的形态。两者都对,只有记录下来的比例才能让读者分清它们。

然后保留原始行。去重后的表只是一个视图,能从原始输入重建它,才使结果可以复现。

公布覆盖范围的声明

说明来源是如何选定的、它们覆盖哪些区域或网络,以及哪些内容被有意排除。

私人的企业端点和未公布的部署从不出现在公开列表中,所以目录里没有,只能证明该目录没有列出它。发布前要核对来源条款和再分发许可,并删去从来不需要的字段。端点研究很少需要订户身份、凭据或浏览历史。公布那些内容,会是另一个有另一套理由的项目。

wc -l vpn-endpoints.jsonl
jq -r '.unit' vpn-endpoints.jsonl | sort | uniq -c
jq -r '.advertised_country' vpn-endpoints.jsonl | sort | uniq -c | sort -rn | head

这三条命令给出的是行数、单位分布,以及按公布国家划分的覆盖概况。人口变化时要保留带日期的快照,并把陈旧与确认的缺失区分开。有明确人口范围的数据集,胜过声称包含互联网上每一个 VPN 的、没有依据的说法。

相关文章