kaspterio code as a hacker

  • QUIC Loss Detection

  • 总体上QUIC的重传机制吸取了大量TCP重传机制的经验,本章介绍的算法和机制基本上在TCP里都有对应的版本。但是QUIC和 TCP协议上的不同也体现在这些算法/机制上,其中最重要的一个不同点是,QUIC中数据传输和数据应用交付在协议上分开的,传输是发生在packet级别的,交付则是发生在stream级别,TCP中两者都是发生在byte stream级别。QUIC packet单调递增的seq number避免了重传歧义,这在TCP里是个比较麻烦的问题。

    经典TCP重传机制

    在正式介绍QUIC的重传机制前,我觉得最好先回顾下TCP对应的重传机制,这部分内容主要来源于《TCP/IP Illustrated》这本书,Richard Stevens大牛已经将TCP协议的big picture总结的明明白白,我们这样的后来人翻翻书就能避免钻进IETF的TCP“故纸堆”中迷失自我了。

    TCP在认为发生丢包时通过重传来解决,因此我们说的重传机制其实最核心的就是TCP在什么情况下认为某个segment丢失了——即loss detection,至于怎么重传在TCP里面是个相对直观的问题,即原样重传那些认为丢失的segment即可,所以有时候会把重传算法和丢包检测算法这两个概念混用。另外TCP重传往往会牵扯到CC算法控制,这里先不做展开。

    总的来说TCP经典的重传机制有两个:基于时间的重传(RTO recovery)和基于ACK结构的重传(fast recovery)

    • 基于时间的重传机制:超时重传需要TCP连接上维护一个重传定时器,当TCP要发送一个新segment时会先取消老的定时器,设置上新的定时器(或者说更新定时器的超时时间),在收到新segment的ACK时取消定时器,如果在定时器到期前没有收到ACK,则触发超时重传,TCP将重传所有未被ACK的segments。这里需要注意的是TCP并不是为每发送的segment都维护一个重传定时器,而是一个连接上只会维护一个定时器,这么做的原因是对端也不是为每个segment都产生ACK,而是会delay cumulative ACK。超时重传对于TCP来说是非常影响性能的事件,第一它将触发CC算法最小化拥塞窗口、第二它将会增加超时时间的backoff。
    • 基于ACK结构的重传机制:TCP规定接收方需要在收到一个乱序到达的segment时立即产生一个ACK(duplicate ACK)。发送方在收到dupthresh次duplicate ACK后将启动快重传,无需等定时器超时。dupthresh值一般是3次。发送方在首次进入快重传的时间点称为recovery point,此时发送方将记录下当前发出去最大的seq number,整个重传recovery过程将持续到收到的ACK匹配或者超过之前记录的最大seq。另外需要注意的是在recovery过程中收到ACK时sender也可能发送新的segment(拥塞窗口允许的情况下)。没有SACK option的情况下,一个RTT只能重传一个segment,如果双方都支持SACK,一个RTT内可以重传多个segment。
    read more...
  • QUIC Connection

  • 0. Overview

    QUIC协议的RFC大概是目前为止我个人读过的最复杂的RFC文档,光是RFC文档都分为了4篇,分别是:

    • RFC 8999规定了QUIC所有版本都将保持不变的一些设计
    • RFC 9000是协议的框架以及除了连接建立外的协议核心部分
    • RFC 9001 是QUIC整合TLS1.3进行密码学握手建立安全的QUIC连接部分
    • RFC 9002 则是关于QUIC丢包检测拥塞控制部分

    RFC 9001在之前的blog中已经做了解读,这篇是继QUIC handshake之后QUIC连接相关的协议解读,主要内容来自于RFC 9000中的第5-第10章节,并按照连接建立、连接迁移、连接终止顺序做了一些内容上的重新组织。另外RFC9000包含的信息量非常大,对很多QUIC设计和行为规定也没有做必要解释,这也造成了阅读体验上枯燥和难懂,因此这篇blog 里尽量对一些我个人认为比较难以理解的点做些motivation上的补充说明。看完并理解这部分内容的话,读者就可以理解QUIC的整个连接建立过程和连接终止过程的工作细节。

    PS: QUIC Connection中有很多地方设计上参考了DTLS,了解下DTLS是怎么做的个人觉得有助于理解QUIC,这部分具体可以参考DTL1.2DTLS1.3

    read more...
  • DTLS1.3

  • 阅读前提:具备密码学基础,并了解TLS1.2、DTLS1.2、TLS1.3的工作细节

    主要内容来源:draft-ietf-tls-dtls13-43

    1. Overview of DTLS1.3

    DTLS1.3 总体上和DTLS1.2的设计原则区别不大,主要区别分为两方面:

    一方面是为了适配TLS1.3 对TLS1.2的升级,除了和DTLS1.2一样要解决TLS在握手阶段、应用层数据传输阶段的有序性/可靠性依赖问题外,还要解决类似比如TLS1.3中引入了key/IV update支持握手完成后的密钥更新,DTLS1.2中就已经引入的epoch 字段重要性上来了,用于标识key phase;再比如TLS1.3支持0-rtt data,在DTLS1.3使用epoch来标识0-rtt data的开始和结束,而非依赖end of early data。

    另一方面是DTL1.3对自身的优化,这里借鉴吸收了不少QUIC的经验,首先是connection ID成为协议原住民了、并且支持ConnectionID的更新(类似QUIC);再比如record的header不再是固定长度了(对应QUIC里的long header & short header);再比如record header里的sequence number也需要加密了(对应QUIC的header encrption); 最后一点很重要,优化了DTLS1.2中粗糙的handshake消息重传机制,引入了ACK进行细粒度的重传,解决之前一个分片丢失,整个flight所有消息都需要重传的问题(个人觉得这基于属于DTLS1.2的设计缺陷了,使得对handshake的协议分片设计变得没有意义)

    read more...