TCP选项的构造(Linux Vs XP)

本帖最后由 Godbach 于 2011-02-11 13:52 编辑

最近在看TCP的选项部分,无意间比较了 Linux 和 XP 的 SYN 包选项字段,发现两者的实现有一些区别。
上图先:
XP 的 SYN 包选项如下所示:

下载 (33.95 KB)
2011-02-11 13:44


Linux 的SYN 包选项如下图所示:

下载 (31.12 KB)
2011-02-11 13:40


对比以上两个图可以看出:
(1)当前测试的两个操作系统,Linux 和XP 均支持四个 TCP 选项:MSS,SACK,Timestamp 和 Wscale。
(2)Linux 仅用了 20 个字节存储这 4 个选项,而 XP 用了 24 个字节。

原因:
在选项构建的时候,每一个选项都是要考虑 32 bit 对齐的。因此,如果单独考虑某一个选项时,尤其是对于长度为非 32bit 整数倍的选项时,要处理对齐的问题,就要考虑 pad 若干个 NOP 字节:
(1)对于 SACK 选项,该选项本身就是 2 个字节: 04 02。因此,要考虑 pad 两个 NOP 字节。所以就变成了: 01 01 04 02,这正如 XP 所实现的。(至于是在选项前面还是后面 pad,本人并没有深入研究。只是当前抓包来看,Linux 和 XP 都是在前面 pad)。
(2)对于 Timestamp 选项,该选项时 10 个字节。因此,考虑 32bit 对齐的话,需要再 pad 两个字节,所以就变成了: 01 01 XX XX ... XX XX,这也正如 XP 实现的。

但是,如果系统同时支持 SACK 和 Timestamp 选项的话呢,正好长度是 2 + 10 = 12,满足了 32bit 的边界。如果确定系统同时支持这两个选项,那么可以考虑将 SACK 选项的两个字节放前面,后面跟上 10 个字节的 Timestamp 选项,这样就需要不需要 pad 了。这正如 Linux 的实现。这样做就节省了 4 个字节的 NOP。

Linux 的内核源码我们可以看到,那就从代码上再次确认一下(2.6.24.4, tcp_output.c):


QUOTE:
static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack,
                                  int offer_wscale, int wscale, __u32 tstamp,
                                  __u32 ts_recent, __u8 **md5_hash)
{
         /*此处省略几百字。。。 */
        *ptr++ = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | mss);
        if (ts) {
                if (sack)
                        *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | /*支持 SACK,先构建 SACK,再构建 Timestamp*/
                                       (TCPOLEN_SACK_PERM << 16) |
                                       (TCPOPT_TIMESTAMP << 8 ) |
                                       TCPOLEN_TIMESTAMP);
                else
                        *ptr++ = htonl((TCPOPT_NOP << 24) |  /*没有 SACK,需要 pad 两个字节的 NOP*/
                                       (TCPOPT_NOP << 16) |
                                       (TCPOPT_TIMESTAMP << 8 ) |
                                       TCPOLEN_TIMESTAMP);
                *ptr++ = htonl(tstamp);                /* TSVAL */
                *ptr++ = htonl(ts_recent);        /* TSECR */
        } else if (sack)



细微之处,可见 Linux 实现之巧妙。

作者: Godbach   发布时间: 2011-02-11

MS 坛子里搞 TCP 的朋友们不多,或者都深藏不露啊。

作者: Godbach   发布时间: 2011-02-12

本帖最后由 raintung 于 2011-02-12 14:01 编辑

此处略去若干个字。。。。

对syn包来说也就是第一次握手而已,而且还是用一个数据包传输, 省4个字节用处并不是很大。

不过从程序角度考虑,linux更多专研于细节

作者: raintung   发布时间: 2011-02-12

是的。 SYN 包本身也不带载荷,选项多几个字节少几个字节,对于传输的影响不是特别大。

作者: Godbach   发布时间: 2011-02-12