TCP选项的构造(Linux Vs XP)
时间:2011-02-11
来源:互联网
本帖最后由 Godbach 于 2011-02-11 13:52 编辑
最近在看TCP的选项部分,无意间比较了 Linux 和 XP 的 SYN 包选项字段,发现两者的实现有一些区别。
上图先:
XP 的 SYN 包选项如下所示:
Linux 的SYN 包选项如下图所示:
对比以上两个图可以看出:
(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):
细微之处,可见 Linux 实现之巧妙。
最近在看TCP的选项部分,无意间比较了 Linux 和 XP 的 SYN 包选项字段,发现两者的实现有一些区别。
上图先:
XP 的 SYN 包选项如下所示:
Linux 的SYN 包选项如下图所示:
对比以上两个图可以看出:
(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)
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更多专研于细节
此处略去若干个字。。。。
对syn包来说也就是第一次握手而已,而且还是用一个数据包传输, 省4个字节用处并不是很大。
不过从程序角度考虑,linux更多专研于细节
作者: raintung 发布时间: 2011-02-12
是的。 SYN 包本身也不带载荷,选项多几个字节少几个字节,对于传输的影响不是特别大。
作者: Godbach 发布时间: 2011-02-12
相关阅读 更多
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28