TCP SYN握手报文可以传输数据吗

TCP握手期间可以传输数据吗?我不是说第三次握手的ACK是否能携带数据,显而易见是可以的,也是简单的。我是在问,client发往server的第一个SYN报文,以及server回复client的第二个SYN/ACK报文,能携带数据吗?

可以!不过声明,本文的内容与TCP Fast Open无关,说的是原始TCP。亦与安全无关,安全的归安全。

依据如经典RFC793 3.4节所示:

Several examples of connection initiation follow. Although these examples do not show connection synchronization using data-carrying segments, this is perfectly legitimate, so long as the receiving TCP doesn’t deliver the data to the user until it is clear the data is valid (i.e., the data must be buffered at the receiver until the connection reaches the ESTABLISHED state). The three-way handshake reduces the possibility of false connections. It is the implementation of a trade-off between memory and messages to provide information for this checking.

此外,《TCP/IP详解(第二版) 卷1》13.2节有如下Note:
在这里插入图片描述
诸如“TCP为什么要3次握手,2次可以吗?”,“TCP握手的必要性”等,亦参考RFC793 3.4节,两三页胜过大书特书。比如本文不会解释3次握手是为了初始化双向的序列号这种众所周知的事。

没人在SYN报文中携带数据的原因是sockets API不支持这么做,进而TCP协议的实现也就没了支持的必要,以下是Linux TCP处理SYN报文的实现片段:

static void tcp_openreq_init(struct request_sock *req,
                             const struct tcp_options_received *rx_opt,
                             struct sk_buff *skb, const struct sock *sk)
{
        struct inet_request_sock *ireq = inet_rsk(req);
        ...
        tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq;
        tcp_rsk(req)->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
        ...

Linux TCP server处理SYN报文时忽略了携带的数据。但如RFC 793所述,SYN报文是可以“捎带”数据的,为什么不呢?怎么想都是可以的。

也许MSS尚未协商,也许rwin尚未知晓,但依TCP语义,receiver可尽力接收,只需回复正确的ACK指示sender的UNA。

唯一问题在于内存开销。

若syncookie未启用,TCP在握手尚未完结前,需缓存任何收到的数据,待连接ESTABLISH之后方可push至应用层,期间,过多sender假冒过量连接,将很容易使receiver内存溢出,表现攻击特征。

但安全的归安全,TCP的归TCP。

至少可做配置开关,在额外机制保证安全的情形下支持SYN携带数据。2022年,安全早就从TCP协议分离了,指望TCP协议本身保证安全,属实不现实。

若死活不支持SYN携带数据,便减少了很多可能:
在这里插入图片描述
起初是sockets API,导致各TCP实现均不支持SYN携带数据,这反使人们偏见于HTTP,TCP握手带来的额外RTT开销让HTTP协议饱受诟病!最终QUIC宣称的0RTT反而成了一个广而告之的新鲜特征。

握手开销无关HTTP,亦无关TCP协议,而是原生于sockets API约束的TCP实现问题。握手开销竟成TCP污点。

基因决定了死亡方式。TCP有很多致命缺陷,滑动窗口,自时钟都是,但握手开销不是。

关于TCP SYN报文携带Payload的有趣玩法,参见前年写的一篇短文:
https://blog.csdn.net/dog250/article/details/108540823

提到TCP和UDP的性能对比,总有人提到TCP有三次握手开销,说的就好像这三次握手是什么正事儿都没干,平白浪费的一样,这些人也是不懂装懂。如果你要建立一个可靠,保序的UDP连接,比如QUIC,你照样逃避不了握手,只不过这些都在UDP上层做了而已。有人说QUIC的0-RTT,TCP对此完全无力,但事实上并不是。0-RTT并非凭空的,背后依然是一次建立多次使用的理念,实质上还是一种cache,类似TCP的Fast Open,但其实无论是TCP还是Self-Defined-Protocol,都是可以无cache直接传输数据的,都是天然的支持0-RTT。那为什么都不能直接传数据,还是因为“一旦出错,代价太大”,trade-off之后,加入纯握手,减少出错代价(比如避免有意为之的攻击),在此基础上用最最传统的cache思路优化,就有了QUIC 0-RTT,以及TCP Fast Open。牵扯太多,写篇小文。

浙江温州皮鞋湿,下雨进水不会胖。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值