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的结构,我还没有深入的学习,简单的字段解释如下:

举例来说,我用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的结构:

image_thumb1

同样是上面的包,TCP 段和其后紧跟的Data段的信息整理出来如下:

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port: d4e8 | Destination Port: 26a1 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number: ffb2 cf43 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number: 8c61 fa60 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|DO: 8 |Reserved: 0| Flags: 18| Window: 0802 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum: fe35 | Urgent Pointer: 0000 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TCP Options: 0101 080a |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TCP Options: 01b2 e00a |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TCP Options: 01b2 d023 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data: 6865 6c6c 6f20 776f 726c 647e 0a |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    

上面Data段的ascii码值为:”hello world~\n”

我在本机上截获的数据包如下,这里我用黄色背景表示IP段,用绿色背景表示TCP段,没有背景则是数据段。蓝色的字体是我的注释。

<1>00:05:20.346307 IP localhost.54504 > localhost.9889: 
Flags [S], seq 4289908546 (client ISN) , win 32792, 
options [mss 16396,sackOK,TS val 28495907 ecr 0,nop,wscale 4], length 0
0x0000:  4500 003c 1f61 4000 4006 1d59 7f00 0001  E..<.a@.@..Y....
0x0010:  7f00 0001 d4e8 26a1 ffb2 cf42 0000 0000  ......&....B....
0x0020:  a002 8018 fe30 0000 0204 400c 0402 080a  .....0....@.....
0x0030:  01b2 d023 0000 0000 0103 0304            ...#........
<2>00:05:20.346333 IP localhost.9889 > localhost.54504: Flags [S.], 
seq 2355231327 (server ISN) , ack 4289908547 (ack=client ISN+1) , win 32768, 
options [mss 16396,sackOK,TS val 28495907 ecr 28495907,nop,wscale 4], 
length 0
0x0000:  4500 003c 0000 4000 4006 3cba 7f00 0001  E..<..@.@.<.....
0x0010:  7f00 0001 26a1 d4e8 8c61 fa5f ffb2 cf43  ....&....a._...C
0x0020:  a012 8000 fe30 0000 0204 400c 0402 080a  .....0....@.....
0x0030:  01b2 d023 01b2 d023 0103 0304            ...#...#....
<3>00:05:20.346347 IP localhost.54504 > localhost.9889: Flags [.], 
ack 2355231328 (ack=server ISN+1) , win 2050, 
options [nop,nop,TS val 28495907 ecr 28495907],length 0
0x0000:  4500 0034 1f62 4000 4006 1d60 7f00 0001  E..4.b@.@..`....
0x0010:  7f00 0001 d4e8 26a1 ffb2 cf43 8c61 fa60  ......&....C.a.`
0x0020:  8010 0802 fe28 0000 0101 080a 01b2 d023  .....(.........#
0x0030:  01b2 d023                                ...#
#tcp 3 way handshake,可以看出,这3个包都没有包含数据,
#由于第一次和第二次握手含有最大报文长度而第三次只含有时间戳
#所以TCP Header的长度不同。

<4>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                                       .
<5>00:05:36.631964 IP localhost.9889 > localhost.54504: Flags [.], 
ack 4289908560, win 2048, options [nop,nop,TS val 28499979 ecr 28499978],
length 0
0x0000:  4500 0034 2a43 4000 4006 127f 7f00 0001  E..4*C@.@.......
0x0010:  7f00 0001 26a1 d4e8 8c61 fa60 ffb2 cf50  ....&....a.`...P
0x0020:  8010 0800 fe28 0000 0101 080a 01b2 e00b  .....(..........
0x0030:  01b2 e00a                                ....
<6>00:05:36.632024 IP localhost.9889 > localhost.54504: Flags [P.], 
seq 2355231328:2355231341, ack 4289908560, win 2048, 
options [nop,nop,TS val 28499979 ecr 28499978], length 13
0x0000:  4500 0041 2a44 4000 4006 1271 7f00 0001  E..A*D@.@..q....
0x0010:  7f00 0001 26a1 d4e8 8c61 fa60 ffb2 cf50  ....&....a.`...P
0x0020:  8018 0800 fe35 0000 0101 080a 01b2 e00b  .....5..........
0x0030:  01b2 e00a 6865 6c6c 6f20 776f 726c 647e  ....hello.world~
0x0040:  0a                                       .
<7>00:05:36.632078 IP localhost.54504 > localhost.9889: Flags [.], 
ack 2355231341, win 2050, options [nop,nop,TS val 28499979 ecr 28499979],
length 0
0x0000:  4500 0034 1f64 4000 4006 1d5e 7f00 0001  E..4.d@.@..^....
0x0010:  7f00 0001 d4e8 26a1 ffb2 cf50 8c61 fa6d  ......&....P.a.m
0x0020:  8010 0802 fe28 0000 0101 080a 01b2 e00b  .....(..........
0x0030:  01b2 e00b                                ....
#4,5,6,7这4个包表示client向server发送了"hello world~\n",
#然后server回射给client

<8>00:06:11.448332 IP localhost.54504 > localhost.9889: Flags [P.], 
seq 4289908560:4289908587, ack 2355231341, win 2050, 
options [nop,nop,TS val 28508683 ecr 28499979], length 27
0x0000:  4500 004f 1f65 4000 4006 1d42 7f00 0001  E..O.e@.@..B....
0x0010:  7f00 0001 d4e8 26a1 ffb2 cf50 8c61 fa6d  ......&....P.a.m
0x0020:  8018 0802 fe43 0000 0101 080a 01b3 020b  .....C..........
0x0030:  01b2 e00b 6162 6364 6566 6768 696a 6b6c  ....abcdefghijkl
0x0040:  6d6e 6f70 7172 7374 7576 7778 797a 0a    mnopqrstuvwxyz.
<9>00:06:11.448524 IP localhost.9889 > localhost.54504: Flags [P.], 
seq 2355231341:2355231368, ack 4289908587, win 2048, 
options [nop,nop,TS val 28508683 ecr 28508683], length 27
0x0000:  4500 004f 2a45 4000 4006 1262 7f00 0001  E..O*E@.@..b....
0x0010:  7f00 0001 26a1 d4e8 8c61 fa6d ffb2 cf6b  ....&....a.m...k
0x0020:  8018 0800 fe43 0000 0101 080a 01b3 020b  .....C..........
0x0030:  01b3 020b 6162 6364 6566 6768 696a 6b6c  ....abcdefghijkl
0x0040:  6d6e 6f70 7172 7374 7576 7778 797a 0a    mnopqrstuvwxyz.
<10>00:06:11.448578 IP localhost.54504 > localhost.9889: Flags [.], 
ack 2355231368, win 2050, options [nop,nop,TS val 28508683 ecr 28508683], 
length 0
0x0000:  4500 0034 1f66 4000 4006 1d5c 7f00 0001  E..4.f@.@..\....
0x0010:  7f00 0001 d4e8 26a1 ffb2 cf6b 8c61 fa88  ......&....k.a..
0x0020:  8010 0802 fe28 0000 0101 080a 01b3 020b  .....(..........
0x0030:  01b3 020b                                ....
#8,9,10包的功能和4,5,6,7类似,表示client向server发送了
#"abcdefghijklmnopqrstuvwxyz\n",然后server回射给client,
#但是这里第9个包的功能相当于5,6包的合并,为什么会出现这种情况?有待考证。
<11>00:06:14.752733 IP localhost.54504 > localhost.9889: Flags [F.], 
seq 4289908587, ack 2355231368, win 2050, 
options [nop,nop,TS val 28509509 ecr 28508683], length 0
0x0000:  4500 0034 1f67 4000 4006 1d5b 7f00 0001  E..4.g@.@..[....
0x0010:  7f00 0001 d4e8 26a1 ffb2 cf6b 8c61 fa88  ......&....k.a..
0x0020:  8011 0802 fe28 0000 0101 080a 01b3 0545  .....(.........E
0x0030:  01b3 020b                                ....
<12>00:06:14.753693 IP localhost.9889 > localhost.54504: Flags [F.], 
seq 2355231368, ack 4289908588, win 2048, 
options [nop,nop,TS val 28509509 ecr 28509509], length 0
0x0000:  4500 0034 2a46 4000 4006 127c 7f00 0001  E..4*F@.@..|....
0x0010:  7f00 0001 26a1 d4e8 8c61 fa88 ffb2 cf6c  ....&....a.....l
0x0020:  8011 0800 fe28 0000 0101 080a 01b3 0545  .....(.........E
0x0030:  01b3 0545                                ...E
<13>00:06:14.753727 IP localhost.54504 > localhost.9889: Flags [.], 
ack 2355231369, win 2050, options [nop,nop,TS val 28509509 ecr 28509509], 
length 0
0x0000:  4500 0034 1f68 4000 4006 1d5a 7f00 0001  E..4.h@.@..Z....
0x0010:  7f00 0001 d4e8 26a1 ffb2 cf6c 8c61 fa89  ......&....l.a..
0x0020:  8010 0802 fe28 0000 0101 080a 01b3 0545  .....(.........E
0x0030:  01b3 0545                                ...E

#11,12,13包是关闭TCP的连接,理论上来说这里应该有4个包,
#因为需要4次握手才能关闭双方的TCP连接。这里我是这样理解的:
#之所以4次握手,是因为当client发送FIN给server后,
#表示client将不会再有数据发送过来,但是server还可能发送数据给client,
#比如telnet一个bbs,退出的时候可能跟你说句Goodbye然后才server才断开连接,
#这时候抓的包应该是4次,但是这里client断开后server也立刻断开了,
#所以server的ack和FIN一起发送了。这只是我的猜想,还有待进一步验证。
    

从这里可以看出tcpdump功能的强大。

tcpdump查看三次握手 - April 6, 2012 -