Tcpdump查看三次握手
April 6, 2012
以前学TCP三次握手也就停留在知道有三个箭头的程度,现在借助tcpdump这个工具可以很清晰的看出TCP协议是怎么建立连接以及传输数据的。
我首先运行了UNP书上的TCP回射服务器的程序,让其在9889端口监听,然后用tcpdump程序来截取本机的9889端口的通信数据包。命令行如下:
$ sudo tcpdump -i lo 'port 9889 and tcp' -X -s 0 -S
具体tcpdump的命令参数可以通过man tcpdump得知,不过这里用的比较重要的就是-X和-S,-X表明当分析和打印时, tcpdump 会打印每个包的头部数据, 同时会以16进制和ASCII码形式打印出每个包的数据(但不包括连接层的头部).
-S表明打印TCP 数据包的顺序号时, 使用绝对的顺序号, 而不是相对的顺序号.比如我第一次用tcpdump查看tcp的三次握手时发现第三次握手的ack=1,这个ack就是相对的,因为tcpdump只在SYN包中显示绝对顺序号,而非SYN包则显示相对的,为了便于观察,在抓包时都采用来绝对的顺序号。
为了能看懂tcpdump输出的格式,首先要知道TCP/IP的数据封装,大体如下图所示:
图片来自http://www2.meps.tp.edu.tw/documents/memo/TCP%EF%BC%8FIP%E6%A6%82%E8%AB%96/index.htm
上面命令-X参数限定了只截取上图中倒数第二个数据包,也就是只包含IP Header,TCP Header,Application Data.
首先看IP Header的结构:
![image][/images/tcpdump/image22_thumb.png]
关于IP Header的结构,我还没有深入的学习,简单的字段解释如下:
-
Version:<4bits>
,表明IP的版本,一般应该都是4或者6.
-
IHL:<4bit>
,Internet Header Length,表明IP头的长度,一个单位长度是32bit,上图中Options字段是非必须的,所以IP Header的长度最小是5x32bits.所以该字段最小值应该为5.
-
Total Length:<16bits>
,该字段表明了整个IP包的长度,包括IP Header,TCP Header和Application Data.
-
IP Source Address:<32bits>
,源IP地址,图中的Adresse是德文的Address,这个IP Header的图和下面TCP Header的图都是从德文网站http://www.trojaner-und-sicherheit.de/tcp-ip-schulung/sld106.htm上面找到的。
-
IP Destionation Address:<32bits>
,目的IP地址。
-
Options:可选字段,后面的Padding表示不够32bits要用0来补齐。
举例来说,我用tcpdump抓到了这样一个包:
00:05:36.631501 IP localhost.54504 > localhost.9889:
Flags [P.], seq 4289908547:4289908560, ack 2355231328,
win 2050, options [nop,nop,TS val 28499978 ecr 28495907], length 13
0x0000: 4500 0041 1f63 4000 4006 1d52 7f00 0001 E..A.c@.@..R....
0x0010: 7f00 0001 d4e8 26a1 ffb2 cf43 8c61 fa60 ......&....C.a.`
0x0020: 8018 0802 fe35 0000 0101 080a 01b2 e00a .....5..........
0x0030: 01b2 d023 6865 6c6c 6f20 776f 726c 647e ...#hello.world~
0x0040: 0a
可以看到第一个32bits的数据为4500,根据上面IP Header的定义,这个IP Header的长度为5,也就是5x32bits,将其整理出来如下:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Ver: 4 |IHL: 5 | ToS: 00 | Total Length: 0041 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Identification: 1f63 |F: 4 | Fragment Offset: 000 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TTL: 40 | Protocol: 06 | Header Checksum: 1d52 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address: 7f00 0001 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address: 7f00 0001 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
下面是TCP Header的结构:
-
Source Port:<16bits>
,源端口
-
Destination Port:<16bits>
,目的端口。
-
Sequence Number:<32bits>
,这个地方还有待研究,目前我是这样认为的,如果本TCP Header中的SYN(Synchronize sequence numbers)标志为0,则代表本TCP Header携带的数据第一个字节的序号;如果本TCP Header中的SYN标志为1,那么这个序号代表了ISN(initial sequence number),也就是双方建立TCP连接时的初始序列号,那么本次TCP连接后在此方向上传输的第一个字节的编号应该为ISN+1.
-
Acknowledge Number:<32bits>
,这个字段仅当TCP Header中ACK标志为1时有效,代表了这个TCP Header的发送端所期望的下一个数据的序列号,与上文提到的Sequence Number配合使用。一旦两端通过TCP连接起来,那么这个字段应该总是有效的。
-
Data Offset:<4bits>
,与IP Header中的IHL类似,单位长度也是32bits,代表了TCP Header的长度,TCP Options也是可选的,但是一般都会存在,所以这个字段的最小值为5,但是一般都会大于5.
-
Options:不定长,每个选项的开始是1字节的kind字段,说明选项的类型。Kind=0:选项表结束(1字节),Kind=1:无操作(1字节),Kind=2:最大报文段长度(4字节),Kind=3:窗口扩大因子(4字节),Kind=8:时间戳(10字节)
-
Data:终于,这个字段就是Application Data,我们要发送的数据就在这里。
同样是上面的包,TCP 段和其后紧跟的Data段的信息整理出来如下:
上面Data段的ascii码值为:”hello world~\n”
我在本机上截获的数据包如下,这里我用黄色背景表示IP段,用绿色背景表示TCP段,没有背景则是数据段。蓝色的字体是我的注释。
从这里可以看出tcpdump功能的强大。