从办公室线路和 VPN 出口运行同样的端口检查,两个答案可能在一个没人改动过的地址上互相矛盾。这个差距来自路径以及究竟由哪台主机作答,而不来自服务是否在运行。三个问题把这些解释分开:探测实际问了什么、哪台主机回答、以及你自己的服务器记录了什么。按这个顺序走一遍,并在进入下一个问题前把每个答案写下来。

先固定探测,再比较两次运行

只有当两个状态词出自同一个实验时,它们才可比较。五个字段把这件事固定下来:远端看到的源地址、解析出的目的地址、端口、扫描类型和时间。改动其中任何一项,你做的就是第二个实验,而不是把第一个实验测了两遍。

先检查来源,因为 VPN 客户端可能开着,而流量仍然从物理接口出去。问远端看到了什么,然后问内核选了哪个接口:

curl -s https://ifconfig.me
ip route get 203.0.113.20

不同网络上的两个地址意味着解释已经在手,其余检查只会确认它。当两者一致时,带着原因标志记录探测,让状态返回时绑定一个解释,而不是孤零零地作为一个光秃秃的词。扫描类型也属于这份记录,因为它描述的是问了什么,而不是回来了什么。没有来源、没有方法、没有时间戳的状态无法与任何东西比较:

nmap -sT -p 443,8443 --reason 203.0.113.20

把该输出保存在记录旁边,而不是放在下一个人看不到的滚动缓冲区里。两次诚实的扫描互相矛盾,只有在没人写下条件时才算争论。条件固定之后,要么结果一致、问题关闭,要么结果不同,而差异是关于路径的事实。

弄清是哪台主机完成了握手

一次完成的握手证明有某台主机完成了它,而那台主机不一定是你想到的那个进程。负载均衡器、反向代理或 SYN 代理可能在真实服务器参与之前就作答,这是正常设计而非症状。对期望名称有效的证书也无法缩小范围,因为证书描述的是服务关系,并不说明哪台机器终止了连接。

Nmap 的端口状态参考把这当作基础:状态记录的是探测从其发送位置能观察到什么,而不是端口的属性。这样读状态词,两次原本矛盾的运行就开始显得一致而不是相反,问题也从端口是否开放转向谁站在它前面。

在后台而不是从外部回答第二个问题。接受连接却到不了上游的前端,恰好制造出服务健康但应用缓慢的外部图景。只有上游自己的记录能区分这两种情况:

tail -n 5 /var/log/nginx/access.log
ss -ltnp 'sport = :443'

日志行显示应用实际看到的客户端地址,第二条命令显示持有 443 端口的是你的应用还是它前面的某个东西。如果两者对哪个地址连入各执一词,你看到的就是同一个请求的两条腿,工单应当这么写。

在归咎隧道之前检查你自己的规则

有意设置的策略是端口在一个网络上应答、在另一个网络上不应答的最常见原因,也是现有解释中最无趣的一个。访问规则的存在就是为了放行一个来源、丢弃其余来源,所以出口变化正是它们被写出来的那个事件。因此通过 VPN 得到不同的状态,并不说明提供商会检查流量。它说明你的源地址现在不同了,这是一个小得多的主张。

这些规则在服务器上可读,所以去读它们,而不是猜测网络的中间部分。列出提到两个地址段中任何一个的过滤规则,然后检查连接究竟有没有到达守护进程:

nft list ruleset | grep -n -e 203.0.113 -e 198.51.100
journalctl -u sshd -n 50 | grep 203.0.113

第二个结果为空是有信息量的,因为没有任何东西到达守护进程,问题属于某个过滤器、安全组或路径本身。命中意味着服务看到了你的来源并选择了它的回答,而这个决定通常写在你能读到的规则里。两个结果都不支持关于提供商的故事,而且两者都比抓包更省事。

分别读取传输、证书和响应

三层产生三种观察,而测试其中之一的探测无法报告另外两层。把它们作为记录中各自独立的行,而不是折成一个结论,因为每一行都以自己的方式失败,而失败方式会告诉你下一步该看哪里。

ObservationWhat it settlesWhat it leaves open
Connection completedA host on the path accepted the handshakeWhich host, and whether its upstream is reachable
Certificate valid for the nameThe endpoint holds a credential for that nameWhether the process behind it is the one you meant
Expected response bodyThe application handled the requestAnything about other ports or other paths
Connection refusedA host replied and nothing was listeningWhether a filter sits ahead of the refused port
TimeoutNo reply arrived before the deadlineDrop, blackhole route or an overloaded host

一条命令会对你控制的服务产生前三行。把它的输出放在扫描旁边的记录里,而不是聊天消息里:

curl -v --resolve office.example:443:203.0.113.20 https://office.example/

按顺序读取输出:握手回答传输问题,证书主体回答名称问题,响应体回答应用问题。当握手行成功而响应行不成功时,你面对的是上游损坏的前端,而不是被封锁的端口。那是与你原先开的工单不同的另一张工单,值得直说。

最后把四个事实写进工单:源地址、扫描类型、作答的主机和时间。后续比较所需的一切都活在这四项里,而下一个接手案件的人不会拥有你的终端历史。如果这四项填不全,这次运行就没有完成。

相关文章