The previous article introduced the principle and use of TCP Fast Open . This time use the tcpdump tool to capture TCP messages to see how it is implemented.
First of all, we must understand the format of the IP header and the TCP header, so as to correspond to the header content according to the protocol:
Next, let’s take a look at the content of the packet capture during the first connection:
packet capture command:
tcpdump -i lo tcp port 5555 -Xnn
SYN+空Cookie:
16:38:18.614264 IP 127.0.0.1.52868 > 127.0.0.1.5555: Flags [S], seq 2089549908, win 43690, options [mss 65495,sackOK,TS val 49428115 ecr 0,nop,wscale 7,tfo cookiereq,nop,nop], length 0
0x0000: 4500 0040 4:版本 | 5:IP报文长度,5*32=5*4字节=5*2个4位16进制=10个4位16进制 | 00服务类型 | 0040:总长度64个字节=32个4位16进制
36c7 4000 36c7:标识,IP报头的序列号 | 010:0未使用,1允许分段,0没有更多分段在传输 | 后面的0表示偏移,这里偏移是0
4006 05ef 40:生存时间 | 06:TCP协议 | 05ef:报头校验和
7f00 0001 7f00 0001:源IP地址7f.00.00.01=127.0.0.1
0x0010: 7f00 0001 7f00 0001:目的IP地址7f.00.00.01=127.0.0.1 | ***因为IP报头长度是10个4位16进制,所以到此,IP报头结束,下面是TCP报头
-------------------------------------------------------------------------------------------------------------------------------------------------------
ce84 15b3 ce84:源端口52868 | 15b3:目的端口5555
7c8c 0054 7c8c 0054:请求端序列号
0000 0000 0000 0000:请求端确认号0
0x0020: b002 aaaa b:数据偏移,TCP头部长度,10*32字节=10*2个4位16进制=20个4位16进制,刚好到结束,也就是该消息没有数据 | 保留6位0 |
000010:URG(0),ACK(0),PSH(0),RST(0),SYN(1),FIN(0) | aaaa:窗口43690
fe34 0000 fe34:校验和 | 0000:紧急指针
0204 ffd7 02:TCP选项,kind=2 最大报文段长度(MSS)选项 | 04:length=4 | ffd7:最大报文段长度65495(mss)
0402 080a 04:TCP选项,kind=4 选择性确认(Selective Acknowledgment,SACK)选项 | 02:length=2 |
08:TCP选项,kind=8 时间戳选项 | 0a:length=10 也就是后面8个字节都是属于这个选项的
0x0030: 02f2 3693 02f2 3693:时间戳值
0000 0000 0000 0000:时间戳回显应答
0103 0307 01:空操作,一般用于填充4字节整数倍 |
03:TCP选项,kind=3 窗口扩大因子选项:假设TCP头部中的接收通告窗口大小是N,窗口扩大因子(移位数)是M,那么TCP报文段的实际接收通告窗口大小是N*2M,或者说N左移M位。|
03:length=3 | 07:位移数,也就是上面的M,那么实际通告窗口大小就是aaaa*2*7
2202 0101 22:kind=22 fto选项 | 02:length | 0101:nop,nop,fto的cookie值一定要后面加上个nopnop,而实际cookie的长度是length-2,参考 https://tools.ietf.org/html/rfc7413#section-4.1.2
SYN+ACK+Cookie
16:38:18.614275 IP 127.0.0.1.5555 > 127.0.0.1.52868: Flags [S.], seq 2825442661, ack 2089549909, win 43690, options [mss 65495,sackOK,TS val 49428115 ecr 49428115,nop,wscale 7,tfo cookie 32faf79caff51cde,nop,nop], length 0
0x0000: 4500 0048 4:版本 | 5:IP报文长度,5*32=5*4字节=5*2个4位16进制=10个4位16进制 | 00服务类型 | 0048:总长度72个字节=36个4位16进制
0000 4000 0000:标识,IP报头的序列号 | 010:0未使用,1允许分段,0没有更多分段在传输 | 后面的0表示偏移,这里偏移是0
4006 3cae 40:生存时间 | 06:TCP协议 | 3cae:报头校验和
7f00 0001 7f00 0001:源IP地址7f.00.00.01=127.0.0.1
0x0010: 7f00 0001 7f00 0001:目的IP地址7f.00.00.01=127.0.0.1
-------------------------------------------------------------------------------------------------------------------------------------------------------
15b3 ce84 15b3:源端口5555 | ce84:目的端口52868
a868 d565 a868 d565:响应端序列号
7c8c 0055 7c8c 0055:响应端确认号
0x0020: d012 aaaa d:数据偏移,TCP头部长度,13*32字节=13*2个4位16进制=26个4位16进制,刚好到结束,也就是该消息没有数据 | 保留6位0 |
010010:URG(0),ACK(1),PSH(0),RST(0),SYN(1),FIN(0) | aaaa:窗口43690
fe3c 0000 fe30:校验和 | 0000:紧急指针
0204 ffd7 02:TCP选项,kind=2 最大报文段长度(MSS)选项 | 04:length=4 | ffd7:最大报文段长度65495(mss)
0402 080a 04:TCP选项,kind=4 选择性确认(Selective Acknowledgment,SACK)选项 | 02:length=2 |
08:TCP选项,kind=8 时间戳选项 | 0a:length=10 也就是后面8个字节都是属于这个选项的
0x0030: 02f2 3693 02f2 3693:时间戳值
02f2 3693 02f2 3693:时间戳回显应答
0103 0307 01:空操作,一般用于填充4字节整数倍 |
03:TCP选项,kind=3 窗口扩大因子选项:假设TCP头部中的接收通告窗口大小是N,窗口扩大因子(移位数)是M,那么TCP报文段的实际接收通告窗口大小是N*2M,或者说N左移M位。|
03:length=3 | 07:位移数,也就是上面的M,那么实际通告窗口大小就是aaaa*2*7
220a 32fa 22:kind=22 fto选项 | 0a:length |
0x0040: f79c aff5
1cde 0101 32fa f79c aff5 1cde: cookie | 0101 :nop,nop
ACK+Data, the data sent here is "Hello, tcp fast open"
16:38:18.614284 IP 127.0.0.1.52868 > 127.0.0.1.5555: Flags [P.], seq 1:21, ack 1, win 342, options [nop,nop,TS val 49428115 ecr 49428115], length 20
0x0000: 4500 0048 4:版本 | 5:IP报文长度,5*32=5*4字节=5*2个4位16进制=10个4位16进制 | 00服务类型 | 0048:总长度72个字节=26个4位16进制
36c8 4000 36c8:标识,IP报头的序列号,比第一次发送的序列号+1 | 010:0未使用,1允许分段,0没有更多分段在传输 | 后面的0表示偏移,这里偏移是0
4006 05e6 40:生存时间 | 06:TCP协议 | 05e6:报头校验和
7f00 0001 7f00 0001:源IP地址7f.00.00.01=127.0.0.1
0x0010: 7f00 0001 7f00 0001:目的IP地址7f.00.00.01=127.0.0.1
-------------------------------------------------------------------------------------------------------------------------------------------------------
ce84 15b3 ce84:源端口52868 | 15b3:目的端口5555
7c8c 0055 7c8c 0055:请求端序列号
a868 d566 a868 d566:请求端确认序列号
0x0020: 8018 0156 8:数据偏移,TCP头部长度,8*32字节=8*2个4位16进制=16个4位16进制 | 保留6位0 |
011000:URG(0),ACK(1),PSH(1)表示含有数据,RST(0),SYN(0),FIN(0) | 0156:窗口342
fe3c 0000 fe3c:校验和 | 0000:紧急指针
0101 080a 01:空操作,一般用于填充4字节整数倍 | 01:空操作,一般用于填充4字节整数倍 | 08:TCP选项,kind=8 时间戳选项 | 0a:length=10 也就是后面8个字节都是属于这个选项的
02f2 3693 02f2 3693:时间戳值
0x0030: 02f2 3693 02f2 3693:时间戳回显应答
4865 6c6c Hell
6f2c 2074 o,.t
6370 2066 cp.f
0x0040: 6173 7420 6f70 656e ast.open
After disconnecting the request, look at the situation of the next request (because a lot of the content is the same, I will not analyze it in detail here, only analyze some key data):
SYN+Cookie+Data
16:38:28.615169 IP 127.0.0.1.52870 > 127.0.0.1.5555: Flags [S], seq 1871838175:1871838195, win 43690, options [mss 65495,sackOK,TS val 49430615 ecr 0,nop,wscale 7,tfo cookie 32faf79caff51cde,nop,nop], length 20
0x0000: 4500 005c bb88 4000 4006 8111 7f00 0001 E..\..@.@.......
0x0010: 7f00 0001
-------------------------------------------------------------------------------------------------------------------------------------------------------
ce86 15b3
6f91 fbdf 6f91 fbdf:请求端序列号1871838175
0000 0000 ........o.......
0x0020: d002 aaaa fe50 0000 0204 ffd7 0402 080a .....P..........
-------------------------------------------------------------------------------------------------------------------------------------------------------
0x0030: 02f2 4057 02f2 4057:时间戳值
0000 0000 0000 0000:时间戳回显应答
0103 0307 01:空操作,一般用于填充4字节整数倍 |
03:TCP选项,kind=3 窗口扩大因子选项:假设TCP头部中的接收通告窗口大小是N,窗口扩大因子(移位数)是M,那么TCP报文段的实际接收通告窗口大小是N*2M,或者说N左移M位。|
03:length=3 | 07:位移数,也就是上面的M,那么实际通告窗口大小就是aaaa*2*7
220a 32fa 22:kind=22 fto选项 | 0a:length | 32fa
0x0040: f79c aff5 1cde 0101 f79c aff5 1cde : cookie | 0101: nop, nop
4865 6c6c 6f2c 2074 Hello,.t
0x0050: 6370 2066 6173 7420 6f70 656e cp.fast.open
SYN + ACK
16:38:28.615198 IP 127.0.0.1.5555 > 127.0.0.1.52870: Flags [S.], seq 2175465761, ack 1871838196, win 43690, options [mss 65495,sackOK,TS val 49430615 ecr 49430615,nop,wscale 7], length 0
0x0000: 4500 003c 0000 4000 4006 3cba 7f00 0001
0x0010: 7f00 0001
-------------------------------------------------------------------------------------------------------------------------------------------------------
15b3 ce86
81aa f921 81aa f921:请求端序列号2175465761
6f91 fbf4 6f91 fbf4:请求端确认号1871838196 = 1871838175 + 21
0x0020: a012 aaaa a:数据偏移,TCP头部长度,10*32字节=10*2个4位16进制=20个4位16进制,刚好到结束,也就是该消息没有数据 | 保留6位0 |
010010:URG(0),ACK(1),PSH(0),RST(0),SYN(1),FIN(0) | aaaa:窗口43690
fe30 0000 0204 ffd7 0402 080a .....0..........
0x0030: 02f2 4057 02f2 4057 0103 0307 ..@W..@W....
ACK
16:38:28.615198 IP 127.0.0.1.5555 > 127.0.0.1.52870: Flags [S.], seq 2175465761, ack 1871838196, win 43690, options [mss 65495,sackOK,TS val 49430615 ecr 49430615,nop,wscale 7], length 0
0x0000: 4500 003c 0000 4000 4006 3cba 7f00 0001
0x0010: 7f00 0001
-------------------------------------------------------------------------------------------------------------------------------------------------------
15b3 ce86
81aa f921 81aa f921:请求端序列号2175465761
6f91 fbf4 6f91 fbf4:请求端确认号1871838196 = 1871838175 + 21
0x0020: a012 aaaa a:数据偏移,TCP头部长度,10*32字节=10*2个4位16进制=20个4位16进制,刚好到结束,也就是该消息没有数据 | 保留6位0 |
010010:URG(0),ACK(1),PSH(0),RST(0),SYN(1),FIN(0) | aaaa:窗口43690
fe30 0000 0204 ffd7 0402 080a .....0..........
0x0030: 02f2 4057 02f2 4057 0103 0307 ..@W..@W....
After reading these contents, the entire TFO process will be clearer.