How Did I Get Here:traceroute 与互联网路径
本文根据 Lexi Mattick 与 Hack Club 的互动网页 How Did I Get Here? 整理。原站点不是普通文章,而是一个会在加载过程中实时生成 traceroute 的网页。
这个网页有趣的地方不只是“解释了 traceroute 和 BGP”,而是它把解释对象变成了页面本身:你打开页面时,服务器会尝试对你的公网 IP 跑一次 traceroute,把路径逐步渲染到页面顶部,然后再解释这些跳点背后是什么。
也就是说,它不是先给你一篇网络科普,再让你想象数据包怎么走;它先把“你是怎么来到这个网页的”展示出来,再从这个结果往回讲互联网的结构。
traceroute 到底在看什么
访问一个网站时,你的设备会把数据包交给下一跳路由器。下一跳再交给它认为更合适的下一跳。这个过程重复很多次,直到数据包到达目标服务器所在的网络。
traceroute 试图把这个路径粗略列出来。它常用的技巧来自 IP/ICMP 里的 TTL:
- TTL 不是实际时间,而是一个跳数计数器。
- 每经过一个路由器,TTL 会减 1。
- TTL 变成 0 时,路由器不再转发数据包,而是向源地址返回错误信息。
- 如果连续发送 TTL 为 1、2、3、4 的探测包,就可以让路径上的路由器逐个暴露自己。
可以把它理解成故意让数据包在第 1 跳、第 2 跳、第 3 跳“过期”,从而逼出每个中间设备的回信。
普通命令行里可以这样观察一个域名路径:
traceroute how-did-i-get-here.net
或者用 mtr 观察更持续的延迟和丢包情况:
mtr how-did-i-get-here.net
这个网页真正做了什么
浏览器打开页面时,网站服务器能看到这次 HTTP 请求来自哪个公网 IP。于是服务端启动作者自己写的 traceroute 程序 ktr,对这个 IP 发起探测。
同时,服务器并不会等 traceroute 全部完成再返回页面。它会先发送 HTML 开头,然后保持 HTTP 连接不关闭。每当 ktr 得到一个新的跳点,服务端就把对应 HTML 继续写进响应流里。
所以从浏览器角度看,这只是一个加载得比较慢的页面;从用户角度看,页面顶部像终端一样逐行出现 traceroute 结果。
更有意思的是,原站点禁用 JavaScript 后仍然能工作。它没有靠前端脚本去轮询结果,而是靠服务端流式输出 HTML。
网页只能从前往后加载,已经发出的 DOM 不能被“倒回去修改”。作者的办法很直接:每次要更新 traceroute 区域时,就继续输出一段新的 HTML 和 CSS,用 CSS 隐藏之前那一版显示结果。浏览器边接收边渲染 CSS,于是用户看到的效果就像页面正在原地刷新。
这个实现很粗糙,但非常符合 Web 的本质:HTTP 流、HTML 流式解析、CSS 即时生效,全部都是浏览器已经具备的能力。
反向 traceroute 的诚实限制
页面标题说的是“我怎么来到这里”,听起来像是在展示用户设备到网站服务器的路径。但网页服务器没有能力在你的电脑上执行 traceroute。
因此它实际做的是反过来:从服务器到你的公网 IP 跑 traceroute,再把结果倒过来展示。
这会带来误差。互联网路由不保证对称:
- 你到服务器可能走路径 A。
- 服务器回你可能走路径 B。
- 任意一个中间自治系统的策略变化,都会让后续路径不同。
所以这个结果不是严格意义上的“你的请求到服务器的完整真实路径”,而是一个近似视角。它仍然有价值,因为两条路径通常会经过相近的网络和运营商,只是具体路由器、入口点和出口点可能不同。
作者没有隐藏这个限制,反而把它作为文章的一部分解释出来。这也是这个网页值得看的地方:它在展示一个技术效果,同时也解释这个效果哪里不可靠。
路径上的网络是什么
traceroute 看到的是一串 IP 或主机名,但页面还会把它们归到不同网络里,例如某个云厂商、某个 ISP、某个骨干网。
这里的“网络”通常指自治系统,也就是 AS。一个 AS 是由同一组织控制的一组路由器、服务器和地址资源。每个 AS 有一个 ASN,例如 AS24940 这样的编号。
互联网并不是一张所有设备彼此直接相连的扁平网络。更准确地说,它是一堆自治系统之间互联形成的网络。你的数据包跨越互联网时,常常是在多个 AS 之间移动:
home network -> ISP AS -> transit AS -> hosting provider AS -> server
这些 AS 之间的连接不是凭空存在的。它们可能来自对等互联,也可能来自付费 transit,也可能来自某种私有商业安排。技术上看是路由,现实里则是合同、机房、端口、线路、成本和策略。
BGP 如何给互联网定形
BGP,也就是 Border Gateway Protocol,是自治系统之间交换路由信息的协议。
边界路由器会告诉它的邻居:“我知道怎么到达这些地址段。”邻居收到以后,把这条路径加入自己的路由表,再继续向其他邻居通告。这样,一条到达某个 IP 前缀的路径就会逐步传播到互联网的其他部分。
一个简化例子:
AS0001 <-> AS0002 <-> AS1234
如果 AS0001 控制某个 IP 段,它会把这个可达性告诉 AS0002。AS0002 再告诉 AS1234:想去那个 IP 段,可以先经过我,再到 AS0001。
当边界路由器要转发一个数据包时,它会在路由表里寻找能覆盖目标 IP 的路径,然后根据多种规则选出“最好”的一条。这里的“最好”不一定是物理距离最短,也可能受到本地策略、商业关系、AS_PATH 长度、偏好值等因素影响。
这也是为什么互联网路径有时看起来“不直”:它不是纯粹的几何最短路,而是网络之间关系和策略共同计算出来的结果。
WHOIS 为什么难解析
为了把 traceroute 的 IP 映射到 AS 和公司名称,原站点还做了额外查询。常见数据来源包括 WHOIS 和 PeeringDB。
WHOIS 的麻烦在于,它的协议本身非常薄:连上服务器,发送查询内容,服务器返回一段文本,然后断开连接。至于返回文本长什么样,并没有统一到足以让解析器轻松工作的程度。
很多 WHOIS 结果看起来像结构化字段,但字段名和位置并不稳定。你想找 ASN,有时字段叫 origin,有时叫 originas,有时同一份结果里还会出现多个可能值。
所以作者最后写的不是严格意义上的 parser,而更像一个“模拟人类读 WHOIS 文本”的小程序:在一堆不完全一致的字段里,猜哪一个最像需要的结果。
这也是网络工具经常遇到的现实:协议看起来很老、很简单、很稳定,但真正接入世界各地的实现时,边角情况会不断冒出来。
这篇网页真正有意思的点
它把三个层面的东西叠在了一起。
第一层是产品体验。用户打开页面时,文章不是静态地讲网络路径,而是在眼前生成一个和自己有关的路径。
第二层是 Web 技术。它没有使用 JavaScript 来做实时更新,而是利用 HTTP 流式响应、HTML 顺序解析和 CSS 覆盖来完成一个动态效果。
第三层是互联网结构。traceroute 只是入口,后面真正重要的是 AS、BGP、对等互联、WHOIS 数据和那些让网络“能通”的组织关系。
这比单纯解释 traceroute 更有启发:互联网不是一条线,也不是一个抽象云。它是由许多运营者控制的网络互联而成,数据包每走一步,背后都有协议选择和组织关系。
可以继续看什么
原站点公开了实现代码:
想自己观察路径,可以从这些命令开始:
traceroute example.com
mtr example.com
whois 8.8.8.8
想继续理解 BGP,可以配合这些关键词查资料:
ASNAS_PATHBGP route advertisementPeeringDBRIR
这类工具不会告诉你“互联网的全部真相”,但能让抽象的网络变成可观察的路径。看到路径之后,再去理解路径背后的自治系统和路由协议,很多网络问题会变得具体得多。