打开终端,但打敲下 ping github.com,不开四个包发出去,网页四个包回来,但打延迟 200ms 上下,不开丢包率 0%。网页你满意地点点头,但打切到浏览器,不开地址栏输入 github.com,网页回车——然后就是但打白屏。转圈。不开再转圈。网页最后给你甩一句“连接超时”。但打
这事我遇到过不下十次。不开第一次以为是网页 GitHub 挂了,跑去 status.github.com 一看,人家活得好好的。第二次以为是公司网络抽风,换手机热点,照样打不开。第三次才反应过来:ping 通和打开网页,压根是两码事。
ping 走的是 ICMP 协议,它只负责问一句“你在吗”,对方回一句“我在”。就这么简单。它验证的是你的机器到 GitHub 那台服务器的 IP 层连通性。但浏览器打开网页走的是 TCP,通常是 443 端口上的 HTTPS 请求。中间任何一层出问题,ping 都发现不了。
你 ping github.com 的时候,系统先做了一次 DNS 解析,把域名变成 IP。但这个解析结果可能是个“假”的。国内某些 DNS 服务器返回的 GitHub IP 地址,有时候指向的是被污染或者根本不可达的节点。ping 那个 IP 能通,是因为 ICMP 包小,随便哪个节点都愿意回你一下。但 TCP 握手要建立完整连接,那个节点可能根本不提供 443 服务,或者半路被重置了。
我自己遇到最常见的情况:ping github.com 解析到的是 20.205.243.166,能通。但浏览器实际请求的时候,TLS 握手阶段就被 RST 掉了。你可以在终端里用 curl -v https://github.com 看详细过程,卡在哪一步一目了然。
ICMP 包和 TCP 包在中间设备眼里待遇不一样。很多防火墙或者流量清洗设备对 ICMP 睁一只眼闭一只眼,但对 TCP 443 端口的连接查得特别严。尤其是 TLS 握手时的 SNI 字段,明文写着你要访问哪个域名。设备一看是 github.com,直接丢包或者发 RST。你的浏览器收到 RST,就报“连接被重置”。而 ping 根本没这个字段,自然畅通无阻。
有个很简单的验证方法:telnet github.com 443。如果 ping 通但 telnet 连不上,基本就是 TCP 层被拦了。或者用 nc -zv github.com 443,效果一样。
很多人电脑上挂着代理软件,系统代理设了,但终端不走代理。于是 ping 走直连,通;浏览器走代理,代理本身挂了或者规则写错了,打不开。反过来也有:终端配了代理,浏览器没配。
还有人改过 hosts 文件,把 github.com 指到一个早就失效的 IP。ping 那个 IP 能通,因为那可能是台还活着的服务器,但它不提供 GitHub 的网页服务。你打开浏览器,自然啥也看不到。
先 nslookup github.com 看解析出来的 IP 是不是你预期的。然后 curl -v https://github.com,看卡在 TCP 连接、TLS 握手还是 HTTP 响应。如果是 TLS 握手失败,大概率是 SNI 被干扰。试试 curl --resolve github.com:443:140.82.121.4 https://github.com,手动指定一个已知可用的 IP,绕过 DNS。
如果手动指定 IP 能通,那就是 DNS 的问题。换个干净的 DNS,或者直接写 hosts。如果手动指定 IP 也不通,那就是 TCP 层被拦了,得考虑代理或者换网络环境。
别再用 ping 来判断“能不能上网”了。它只能告诉你路通不通,不能告诉你门开不开。