通过tcpdump学习网络协议
在网络osi的七层模型中,TCP位于第四层-Transport(传输)层,IP在第三层—Network层,ARP在第二层—Data Link层,
在第二层上的数据,我们叫Frame
,在第三层上的数据叫Packet&datagram
,第四层的数据叫Segment
关于这几个术语,wikipedia是这么说的:
The term TCP packet appears in both informal and formal usage, whereas in more precise terminology segment refers to the TCP protocol data unit (PDU), datagram [4] to the IP PDU, and frame to the data link layer PDU
大家意见是不统一的,我们这就frame,packet,segment来分别标识链路层,网络层和传输层
ip packet header
Version
:前四个字节为版本号: 0100 IPv4 , 0110 IPv6Internet Header Length
: IHL ,四个字节, 它是32bits字的数量(32 * IHL),最小为5(0101),最大为15(1111),所以ip头的长度[5*32=160bits=20bytes,15*32=480bits=60bytes]Differentiated Services Code Point && Explicit Congestion Notification
: DSCP && ECN 包的优先级??Total Length
: 16bits 定义了packet的大小,包括头(header)和数据(data),以字节为单位,最小20个字节,最大65535字节Identification
: id标识Flags
: 第一位reserved,必须为0;第二位 DF(Don’t Fragment),DF位设为1时表明路由器不能对上层数据包分片。 如果一个上层数据包无法在不分片的情况下进行转发,则路由器会丢弃该上层数据包并返回一个错误信息; 第三位 MF(More Fragments)当路由器对一个上层数据包分片,则路由器会在除了最后一个分片的IP包的包头中将MF位设为1。Fragment Offset
: 片偏移,长度13比特。表示该IP包在该组分片包中位置,接收端靠此来组装还原IP包.如果packet的大小大于MTU(maximum transmission unit 最大传输单元),就要进行分片.Time To Live
: TTL 长度8比特。当IP包进行传送时,先会对该字段赋予某个特定的值。当IP包经过每一个沿途的路由器的时候,每个沿途的路由器会将IP包的TTL值减少1。如果TTL减少为0,则该IP包会被丢弃,通常会给发送者发送一个ICMP超时消息。 这个字段可以防止由于路由环路而导致IP包在网络中不停被转发Protocol
: 协议 0x01 ICMP, 0x06 TCP, 0x11 UDPHeader Checksum
: 16位,用来做IP头部的正确性检测,但不包含数据部分。因为每个路由器要改变TTL的值,所以路由器会为每个通过的数据包重新计算这个值。校验不通过,会丢到该包.Source address
: 32位,源ipDestination address
: 32位,目的ipOptions
: 松散源路由(给出一连串路由器接口的IP地址,ip包必须沿着这些Ip地址传送,但允许在相继的两个IP地址之间跳过多个路由器);严格源路由;路由记录;时间戳Padding
: 补齐,ip header必须为32bits的倍数
分片
网络协议使得网络可以相互的通信.这种设计为多种不同的物理设备提供了便利,它是独立于它所依赖的链路层 的.不同硬件的网络设备通常具备不同的传输速度,同时也往往有不同的最大传输单元.当一个网络向一个具备较小MTU的网络 传送数据报时,它可能需要对数据报进行分片.在IPv4中,这个功能被放在了网络层,由IPv4的路由器来实现.而在IPv6中,不允许路由器进行分片.主机在发送数据报之前必须能判定传输路径上的MTU.
当一个路由器接收到一个packet时,它检查目的地址,判定即将使用的接口和该接口的MTU.如果Packet的大小大于MTU,并且DF字段被设置为0,路由器就会将packet进行分片 路由器将packet分为多片,每片的大小最大为MTU - ip头的大小(20-60 bytes).每个fragment packet有以下变化:
- total length是fragment的size
- MF 标志被设为1(除了最后一个fragment,它被设为0)
- fragment offset被设置,它是以8byte来度量的
- header checksum被重新计算
eg: 如果MTU为1500 bytes,ip头大小为20,fragment的偏移将是(1500 - 20 ) / 8 = 185的倍数
如果一个传输层的segment的大小为4500bytes,ip头为20bytes,所以ip packet的大小为4500.当这个包经过一个MTU为2500的连接时,它会变成如下两片:
Fragment | Total bytes | Header bytes | Data bytes | MF | Fragment offset(8-byte blocks) |
---|---|---|---|---|---|
1 | 2500 | 20 | 2480 | 1 | 0 |
2 | 2040 | 20 | 2020 | 0 | 310 |
tcp segment header
Source port
: 16位,源端口号Destination port
: 16位,目的端口号Sequence number
:32位 序列号Acknowledgment number
: 32位Data offset
: 4位TCP header的size(20-60)bytesReserved
: 3位NS
: 1位CWR
: 1位ECE
: 1位URG
: 1位 表明Urgent pointer是有意义的ACK
: 1位 表明Acknowledgment 域是有意义的,在初始化的SYN包后的所有的包的这个位都应该被置为1PSH
: 1位 请求推送数据给接收的应用RST
: 1位 重置连接SYN
: 1位 同步序列号.仅当client和server两端第一次发送包时这个位被置为1FIN
: 1位 不再需要数据了Window size
: 16位 接收的窗口大小Checksum
: 16位 校验和Urgent pointer
: 16位 如果URG位被置为1,这表明上一个urgent数据byte相对于它的序列号的偏移Options
:Padding
: 补0,
practice
好了,有了上述基础,我们来实操下吧. dump下线上一个包,tcpdump入门
[chuangjian.li@l-xxxx.f.cn1 ~]$ sudo tcpdump -nnvvX host 218.80.232.44 -c 3
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
20:17:08.896034 IP (tos 0x28, ttl 49, id 16341, offset 0, flags [none], proto TCP (6), length 1400)
218.80.232.44.80 > 10.86.212.176.33314: Flags [.], cksum 0x195c (correct), seq 1024948164:1024949512, ack 2128146148, win 65535, options [nop,nop,TS val 2979322617 ecr 968275531], length 1348
0x0000: 4528 0578 3fd5 0000 3106 a2ff da50 e82c E(.x?...1....P.,
0x0010: 0a56 d4b0 0050 8222 3d17 77c4 7ed8 eee4 .V...P."=.w.~...
0x0020: 8010 ffff 195c 0000 0101 080a b194 daf9 .....\..........
0x0030: 39b6 b64b 4854 5450 2f31 2e31 2032 3030 9..KHTTP/1.1.200
0x0040: 204f 4b0d 0a44 6174 653a 204d 6f6e 2c20 .OK..Date:.Mon,.
0x0050: 3039 204d 6179 2032 3031 3620 3132 3a31 09.May.2016.12:1
0x0060: 343a 3339 2047 4d54 0d0a 5365 7276 6572 4:39.GMT..Server
0x0070: 3a20 4170 6163 6865 0d0a 582d 4672 616d :.Apache..X-Fram
0x0080: 652d 4f70 7469 6f6e 733a 2053 414d 454f e-Options:.SAMEO
0x0090: 5249 4749 4e0d 0a56 6172 793a 2041 6363 RIGIN..Vary:.Acc
0x00a0: 6570 742d 456e 636f 6469 6e67 0d0a 5472 ept-Encoding..Tr
0x00b0: 616e 7366 6572 2d45 6e63 6f64 696e 673a ansfer-Encoding:
0x00c0: 2063 6875 6e6b 6564 0d0a 436f 6e74 656e .chunked..Conten
0x00d0: 742d 5479 7065 3a20 7465 7874 2f78 6d6c t-Type:.text/xml
0x00e0: 3b63 6861 7273 6574 3d55 5446 2d38 0d0a ;charset=UTF-8..
0x00f0: 436f 6e6e 6563 7469 6f6e 3a20 4b65 6570 Connection:.Keep
0x0100: 2d41 6c69 7665 0d0a 0d0a 3166 6638 0d0a -Alive....1ff8..
....
-nn 不解析域名和端口名 -vv 显示多的信息 -X 以ascii显示报文信息,不显示frame头,所以上述的就是一个ip packet.
一个字节一个字节来: 首先IP头
4: Version IPv4 版本4
5: IHL 5 * 4 = 20 bytes ip头大小为20bytes
28: tos 为0x28 ,tos
0578: 十进制1400 ip packet的长度为1400bytes,length
3fd5: 十进制16341 id
0(3bits): DF 与MF都为0 ,说明发生了发片,且不是最后一片
000(13bits): Fragment offset,片偏移为0,分片后的第一片
31: 十进制49 ttl
06: 十进制6,对应tcp协议 Protocol
a2ff: Header Checksum
da50e82c: 0xda十进制218, 0x50十进制80,0xe8十进制232,0x2c十进制44 ,对应源ip218.80.232.44Source address
0a56d4b0: 同上Destination address
刚好20个字节,接下来TCP头
0050: 十进制80,源端口号Source port
8222: 十进制33314,目的端口号Destination port
3d17 77c4: 照不上
7ed8eee4:十进制2128146148,Acknowledgment number
8: 8 * 4= 32 tcp header的大小为32Data offset
0(3bits): 000Reserved
010(9bits): 000010000 ACK
为1 ??
ffff: 65535 窗口大小Window size
195c: Checksum
0000:Urgent pointer
这才20bytes了,还有32-20 =12 bytes 待研究 0101 080a b194 daf9 39b6 b64b
再接下来就是HTTP报文了
4854 5450 2f31 2e31 2032 3030 ….
参考
[wiki百科ip]https://en.wikipedia.org/wiki/IPv4#Header
[wiki百科tcp]https://en.wikipedia.org/wiki/Transmission_Control_Protocol
[Packet Fragmentation]http://www.tech-faq.com/packet-fragmentation.html
[DSCP]https://en.wikipedia.org/wiki/Differentiated_services
[TOS]https://en.wikipedia.org/wiki/Type_of_service
[wiki校验和]https://en.wikipedia.org/wiki/IPv4_header_checksum
[IP头结构详解]http://blog.csdn.net/achejq/article/details/7040687
[tcp的那些事儿[上]]http://coolshell.cn/articles/11564.html
[tcp的那些事儿[下]]http://coolshell.cn/articles/11609.html
- 上一篇 leetcode的脚本全解
- 下一篇 webservice入门