分类:默认分类

从 FACK 到 RACK-TLP:TCP 丢包检测机制的演进与现代化之路

在传输控制协议(TCP)数十年的演进中,丢包检测与恢复机制始终是影响传输性能的核心环节。从最初依赖序列号判断丢包的 Reno 模式,到引入选择性确认的 SACK,再到基于时间判定的 RACK,乃至进一步强化的 RACK-TLP,TCP 的恢复能力经历了逐步现代化的升级。

本文将带你从理论层面,深入理解 TCP 的四种关键丢包检测机制:FACK、SACK、RACK 与 RACK-TLP,并对比它们的工作原理、适用场景与演进关系。

丢包是 TCP 面临的常见网络问题。能否及时发现丢包并快速恢复,直接决定了 TCP 在以下场景中的表现:

  • 弱网或移动网络(丢包率高、时延抖动大);
  • 数据中心高吞吐场景(对恢复速度敏感);
  • 中间设备存在乱序、ACK 压缩行为。

传统 TCP 采用 RTO(Retransmission Timeout) 机制来兜底触发重传。但初始 RTO 延迟高达 1 秒,误判多,恢复慢,成为瓶颈。因此,TCP 社区不断探索更快、更精准的丢包检测算法。

原理:

接收方在 ACK 中显式告诉发送方:“我已经收到哪些数据段”,而不是仅告诉“收到到哪了”。

优点:

  • 精确指出哪些段被接收;
  • 适用于多段丢包场景;
  • 避免不必要的重复重传。

局限:

  • 虽然能知道“哪里没收到”,但仍依赖序列号判断丢包
  • 容易受到网络乱序、ACK 压缩的干扰,误判丢包或延迟重传。

原理:

FACK 在 SACK 的基础上进一步演化。它不仅看 SA...

TLS 1.3 新特性剖析

这里结合 RFC8446MbedTLS 源码, Wireshark 抓包对 TLS 1.3 几个重要特性做深入剖析。

TLS 1.3 对比 TLS 1.2 的主要差异。

重点介绍全新特性前。介绍下 TLS 1.3 的完整握手流程。

如上完整握手流程,包含密钥交换(Key Exchange)和双向认证(Authentication,可选)流程。

  • 对于密钥交换仅支持 ECDHE。
  • 对于认证支持证书认证和 PSK 认证,当然也可以不做认证。

如上 KE 和 Auth 流程组合,TLS 1.3 共支持如下5种模式。

TLS 1.2 PSK KE 对比 TLS 1.3 PSK ECDHE 一个安全特性就是前向安全。 前向安全确保了长期密钥泄露不会影响历史会话的安全性。

以下是 TLS 1.2 PSK KE 与 TLS 1.3 PSK ECDHE 的握手流程对比。在密钥交换过程中,最大的区别在于是否引入了临时椭圆曲线 Diffie-Hellman 的密钥交换。

  • 在 TLS 1.2 PSK KE 模式下,会话密钥完全依赖预共享密钥(PSK),如果 PSK 泄露,攻击者可以离线解密之前或当前的通信内容。

  • 在 TLS 1.3 PSK ECDHE 模式下,引入了临时的 ECDHE ClientShare 和 ServerShare 公钥交换,即使 PSK 被泄露,也无法恢复会话密钥,因此提供了前向安全性。

如下流程...

NS-3 Wi-Fi 仿真模型测试

目前,大多数关于测试和验证的文档都存在于出版物中,以下列出了一些参考文献。

802.11b 错误模型的验证结果可在以下 技术报告 中查看。

需要注意以下两点说明:

上述参考文献中的图 1-4 对应的是 ns-3 NIST 比特错误率(BER)模型。在该论文附录的程序(80211b.c)中,有两个用于生成数据的常量。第一个是分组大小,设置为 1024 字节。第二个是“噪声”,其值设为 7 dB;这一值是通过经验选取的,以使曲线与 CMU 测试床的报告数据最契合。虽然值为 1.55 dB 更符合 CMU 论文报告的 -99 dBm 噪声底限,但噪声系数 7 dB 最适合与 CMU 实验数据拟合。这一默认值 7 dB 是 ns3::YansWifiPhy 模型中的 RxNoiseFigure。更改噪声系数会使曲线向左或向右移动,但不会改变其斜率。

可以通过运行 examples/wireless/wifi-clear-channel-cmu.cc 示例程序重现这些曲线。当启用 GNU 科学库(GSL)时,会生成以下图表:802.11b 的清晰信道(AWGN)错误模型

802.11a/g OFDM 错误模型的验证结果可在以下 技术报告 中查看。 可以通过运行 examples/wireless/wifi-ofdm-validation.cc 示例程序重现这些曲线,以下图表展示了 802.11...

NS-3 Wi-Fi 仿真模型概述

ns-3 节点可以包含多个 NetDevice 对象,就像一台实际的计算机可以包含多个独立的网络接口卡(如以太网、Wi-Fi、蓝牙等)。本章节描述了 ns-3 的 WifiNetDevice 及其相关模型。通过将 WifiNetDevice 对象添加到 ns-3 节点中,可以创建基于 802.11 的基础设施网络和自组织(Ad Hoc)网络模型。

WifiNetDevice 模拟了基于 IEEE 802.11 标准的无线网络接口控制器 [ieee80211]。我们将在后续章节中详细说明,但简单来说,ns-3 提供了以下 802.11 相关模型:

  • 基本的 802.11 分布式协调功能(DCF),支持 基础设施模式自组织模式
  • 802.11a802.11b802.11g802.11n(支持 2.4 GHz 和 5 GHz 频段)、802.11ac802.11ax(支持 2.4 GHz、5 GHz 和 6 GHz 频段)以及 802.11be 的物理层
  • MSDU 聚合MPDU 聚合 的 802.11n 扩展,并支持两者组合(两级聚合)
  • 802.11ax 的 下行链路 OFDMA(DL OFDMA)上行链路 OFDMA(UL OFDMA)(包括多用户增强分布式协调功能(MU EDCA)参数集的支持)
  • 802.11be 的 多链路 发现与设置
  • 基于 QoS 的增强分布式协调功能(E...

GCC 隐藏符号

日常被 GCC 折磨,GCC 链接报错,提示未定义符号。

排查编译流程确认该符号其最终被链接进入 third_party/wireshark/build/run/libwireshark.dylib。

而我最终又链接了 libwireshark.dylib。

并且确认该符号并非 static。

直接查找二进制文件也能够确认其符号已经被链接进入 dylib。

通过 nm 确认符号属性发现其为 t。

再次查看对应的 .o 确认其为 T。

那么该文本符号从 T 变成了 t 只能够是在链接阶段了。最后确认了 -fvisibility=hidden。

这个选项会将所有符号的默认可见性设置为隐藏,除非显式地声明为 default。这意味着,尽管在编译 .o 文件时符号是全局可见的,但在链接生成 .dylib 文件时符号变成了局部可见。

那为什么要这么做呢?

https://gitlab.com/wireshark/wireshark/-/blob/4aa814ac25a18ea48d4002351ed45d4b245b0c08/CMakeLists.txt#L1070-1104

主要目的是设置编译器默认隐藏符号,确保只有显式导出的符号才会在共享库(shared library)中可见。这可以帮助在更多的 Unix 系统上捕捉到符号导出失败的问题,而不仅仅是在 Windows 上。

https://gitlab.com...

聊聊 GCC 中的 int 类型和字节对齐

最近看到一个问题,在 64 位操作系统中。实际测试环境 Ubuntu 22.04,GCC 11。

问 sizeof(stuct test) =?当然我知道这道题想考察的 int/long 定义以及对齐问题,之前编码也不会太在意这类似问题,直接打印出来就行,但是作为考题这里有诸多不严谨地方。我们好好探索下。

不管三七二十一,直接编译打印。

显然地,这里 int 为4个字节,char 被4字节对齐。

看几个 GCC 选项

https://gcc.gnu.org/onlinedocs/gcc-9.5.0/gcc/x86-Options.html#x86-Options

看起来这里默认最大设置都是4字节对齐。

https://gcc.gnu.org/onlinedocs/gcc-9.5.0/gcc/Code-Gen-Options.html#Code-Gen-Options

显然地,这里的编译选项能够设置 long 类型和对齐。先看默认值。

这里能够设置 -m32 将 long 和指针类型设置为 4字节,但是对齐方式还是 4字节。

如下结论。

Thread 路由协议

本文为 Thread 路由协议相关规范,翻译自Thread Specification->5.9 Routing Protocol,作为理论储备。这里未做任何解释,接下来会结合其他系列文档从抓包、代码实现结合协议规范去理解该路由协议。

本节描述了 Thread 网络中使用的路由协议。Thread 路由协议是一个简单的距离向量路由协议。协议的主要目标是最大化地可以在单个消息中传输的路由信息量。因此,该协议限制了包含最多 MAX_ROUTERS 或更少路由器的网络。

路由器定期向 Thread 网络分区中的所有其他路由器广播其路由成本以及与邻居之间的单跳链路质量。到达特定目的地的路由成本是所有邻居对该目的地广播的成本中的最小值加上到该邻居的成本。 Advertisement 发送的速率由 Trickle 算法的一个实例确定RFC 6206

路由器维护一个路由数据库,记录使用 Thread 距离向量路由的每个单独接口的信息。这些数据库包含以下各小节中描述的数据集。

接口的路由器 ID 集包含两个值:

  • ID_set 是当前有效路由器 ID 的集合。
  • ID_sequence_number 是分配给当前 ID_set 的序列号。

接口的链路集记录了与该接口上的其他路由器是或曾是邻居的信息。路由器为与每个邻居的链接维护一个元组,如下所示:(L_router_id, L_link_margin, L_i...

Wi-Fi 6 OFDMA 测试报告

OFDMA 频谱图来源:Gjermund Raaen

我感觉自去年以来我一直在等待。

随着 2018 年的结束,广告支持的崩溃迫使我转向付费咨询。尽管这对我在财务上更有利,但主要关注咨询工作意味着在 2019 年几乎没有发布任何关于 SmallNetBuilder 的产品评论。

我一直在尽力改变这一点。但在努力制定新的 Wi-Fi 测试方法以替代之前侧重速度测试,进而转向以测量 Wi-Fi 产品的质量、稳健性和效率时,我一直遇到障碍。

在完成了 octoScope 平台上的TR-398 Wi-Fi 性能测试套件的自动化后,我一直试图证明 OFDMA,这是 Wi-Fi 6 的一个关键特性,可以产生更高的总吞吐量。简而言之:启用 OFDMA 后,我看到了更高的总吞吐量,但增益是高度可变的。

OFDMA 开始看起来很像 MU-MIMO

正如我在Wi-Fi 6 性能汇总:测试了五台路由器中指出的,测试 OFDMA 的主要障碍之一是迄今市场上的大多数消费级 Wi-Fi 6 产品都没有启用 OFDMA。一次又一次,我被告知新的启用 OFDMA 的固件将在一个月左右发布,但一个月过去了,固件并未更新。在没有要测试的东西时,很难制定测试方法。

截至 2019 年底,美国有四台启用 OFDMA 的 Wi-Fi 6 路由器,如表 1 所示。这是在几乎宣布了几十个 Wi-Fi 6 路由器或网状系统之中的情况。

表1:...

跨源资源共享(CORS)

这里来聊聊跨源资源共享CORS(Cross Origin Resouce Share)。

开局一张图,很多人错误理解跨源资源共享就是浏览器在访问服务器A(domain-a.com)获取的资源如果包含跨源服务器B(domain-a.com)资源的时候那么此时就需要跨源资源共享,所以我们需要配置我们的访问控制策略Access-Control-Allow-Origin 运行所有站点访问。

但是为什么这里跨源资源共享是被服务器B控制的?

原来这里这里跨源资源共享是浏览器用来保护服务器B的,防止服务器A加载的资源伪造一个请求,但是此时浏览器已经记住了服务器B的Cookie认证,从而完一次对服务器B的攻击,这就是跨源请求伪造(Cross-site request forgery)。

假如浏览器没有CORS,会是怎样?我们需要举个栗子:

用户在浏览如上购物网站B(domain-b.com),此时已经完成认证,浏览器会自动将记住服务器B的Cookie,方便你继续浏览。此时我们在新的标签页开始浏览网页访问服务器A(domain-a.com),服务器A加载的JavaScript可以直接对服务器B发起了一次请求获取了你的购物信息。

所以此时服务器B的同源策略就一项非常重要的安全措施。

浏览器有CORS又会是怎样?

对于如上的跨源资源请求浏览器会区分是简单请求还是非简单请求。什么是简单请求?

使用下列方法之一:

GCC 未使用函数、变量和文件优化策略

GCC 优化过于复杂,这里探索 GCC 对未使用的代码和变量以及文件的优化策略。

如下两个文件。

main.c 文件内容如下。

unused.c

  • 默认编译选项,通过可执行文件确定所有变量和函数都未优化。

  • -O1 -O2 -Os 选项,所有static 链接属性的变量和函数被用优化掉。

  • 为 static 链接属性的变量增加 __attribute__((used)) 属性。优化被抑制。

  • 增加 -Wl,--gc-sections 选项,所有的 unused.c 变量和函数,以及 main.c 中的变量全部被优化。

  • 同时使用 -Wl,--gc-sections 和 -O1。进一步优化掉 main.c 中的 static 函数,只剩下最后一个未使用的 extern 函数。

  • 同时使用 -Wl,--gc-sections 和 -O2 或者 -Os 。所有未使用的函数、变量全部被优化。

  • 或者额外指定 -ffunction-sections ,进一步把未使用的函数优化掉。

  • 对于--gc-sections ,通过设置 KEEP 链接抑制变量的优化。注意,并不能对函数使用属性。