深入理解为什么在劫持环境下, Metrics IP 为空

现象回顾

劫持 WIFI 网络环境, Sqi-dns-hijackingcore.sqiapp.com 解析到 203.208.39.99, 已知目标 IP 已开启 443 端口。
你的 NSURLSession 任务在 didFinishCollecting 回调里拿到一条 NSURLSessionTaskTransactionMetrics,但:

(Local Address)   (null)
(Remote Address)  (null)

Apple 的计量规则

localAddress / remoteAddress 只有在 “这条连接被真正用来传输应用层数据” 之后才会被填充。
Apple 文档对两个属性都写着几乎相同的一句(高亮是我加的):

If the app didn’t use the connection, this value is nil

在下面这些情况下,系统会认为“连接没被用过”:

情形 结果 为什么地址为 nil
TLS 握手/证书校验失败
(例如被劫持到 203.208.39.99,证书与 core.sqiapp.com 不匹配,ATS 或你自己的 Pinning 在 ClientHello 之后就终止连接)
task 直接报 NSURLErrorServerCertificateUntrusted 等错误 没有任何应用数据发出,连接标记为 “unused”
域名解析失败 / TCP 握手没做完 地址自然拿不到 同上
iCloud Private Relay 或代理
(isProxyConnection == YES)
地址显示为中转服务器,而不是目标 如果隐私策略再收紧,也可能给 nil
等待网络 (waitsForConnectivity) 时被你自己取消 地址 nil 连接还没真正建立

Apple Developer Forums 的示例日志和本文讨论的现象一模一样:当域名错误或握手失败时,地址字段为 (null)

为什么在 Sqi-dns-hijacking 网络下触发

DNS 指向了 Google 的 203.208.39.99,但
该主机提供的证书不匹配 core.sqiapp.com → ATS 信任评估失败。
URLSession 在 TCP 三次握手后、还没把任何 HTTP 请求数据发出去就中止。
交易记录被标记为 “connection unused”,于是 localAddress / remoteAddress 均为 nil

只要握手失败得足够早,哪怕 443 端口是通的,Metrics 里仍然没有地址。

如何得到真实地址?

让握手成功(取消 Pinning、换成受信证书或临时连真服务器)后再看 Metrics。
改用 Network framework (NWConnection) —— 你可以在还没发 TLS 握手之前就拿到 NWEndpoint 的 IP。
确保设备没开 iCloud Private Relay / VPN / 代理,否则看到的也是中转地址。

小结

NSURLSessionTaskTransactionMetrics 只在 连接真正被“用了” 以后才填写源/目的 IP。
被 DNS 劫持导致 TLS 失败时,连接被视为未使用 → 地址字段是 nil
这完全符合 Apple 的设计,不是 bug,只能通过让连接走到“发出第一字节的 HTTP 请求”这一步才会有地址数据。


拓展之关于Metrics

发音

英, 美 ['metrɪks]

metrics(/ˈmeɪ-trɪks/)= “度量指标、量化衡量值”

场景 常见中文译法 内涵 例子
一般商务 / 产品 指标、衡量标准 用数字衡量目标是否达成 business metrics = “业务指标”(DAU、转化率)
计算机 / 运维 性能指标、监控指标 描述系统健康状态的量化值 CPU metrics, latency metrics
iOS / Apple API Transaction Metrics 对一次网络事务采集到的所有网络性能数据 NSURLSessionTaskTransactionMetrics 内的 fetchStartDate, localAddress
学术 / 质量评价 评价指标 客观度量某对象优劣的数字 evaluation metrics(准确率、召回率)
数学(单数 metric 度量 一种距离函数 欧几里得距离是一种 metric

用法要点

集合名词
metrics 常当不可数集合名词用:

Collect metrics every 30 seconds.

单数 metric = “某一个指标”

Latency is a critical metric for real-time apps.

词源
来自希腊语 metron “量尺”。

在 Apple 网络栈里的含义

NSURLSessionTaskTransactionMetrics 把一次 TCP/TLS 事务的各个 metrics(开始时间、握手耗时、IP 地址等)打包成一个对象,供开发者诊断网络性能。


一句话记住metrics = 一切用数字“量尺”去衡量事物状态或效果的指标

拓展之localAddress vs. remoteAddress

二者一字之差、含义完全相反

属性 中文直译 代表谁的 IP 典型取值示例 何时可能为 nil
localAddress 本地地址 你这台设备 在发起这条网络连接时所用的网络接口 IP(WLAN、蜂窝、VPN 隧道等) 192.168.10.23(Wi-Fi)
10.0.0.4(蜂窝 NAT64)
① 连接因 TLS 或 DNS 错误在真正“用”之前就被放弃;② 构建在匿名代理 / Private Relay 之上并被 Apple 隐私规则隐藏;③ 任务处于等待联网 (waitsForConnectivity) 即被取消 (CSDN博客)
remoteAddress 远端地址 对端主机(或第一跳代理)的 IP —— 即 TCP 三次握手 / QUIC CHLO 时真正握上的目标 203.208.39.99(直连服务器)
172.20.0.8(公司 HTTP 代理)
同上;另外当通过透明代理 / VPN 层封装时,看到的是代理出口而不是最终服务器 (掘金)

一句话记住:

localAddress 看“我是谁”;
remoteAddress 看“我在跟谁直接握手”。


进一步要点

端口配对
同时还有 localPort / remotePort,能让你知道源端口(客户端随机)与目标端口(通常 443、80……)的对应关系。
多路径场景
在 Wi-Fi + 蜂窝共存的 Multipath TCP / QUIC 中,这两个字段记录“首条流”的本地/远端 IP;如果之后系统切到另一条路径,它们不会实时更新。
代理 / VPN / Private Relay
isProxyConnection == YES 时,remoteAddress 是代理节点;再往后的真实服务器地址你拿不到。Private Relay 情况下,苹果为了隐私可能把两端 IP 都置为 nil
nil ≠ BUG
只要操作系统认定“连接尚未被真正用于传输应用层数据”,地址字段按照规范就必须是 nil,与你看到的 Sqi-dns-hijacking 场景一致。

借助这两个字段,你可以快速回答诸如“究竟走 Wi-Fi 还是蜂窝?”、“TCP 打到哪台机器?”之类的疑问——前提是连接已经成功完成且未被额外的隐私层隐藏。

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容