Linux高性能服务器编程 第2章 IP协议详解
文章目录
IP头部信息
出现在每个IP数据报中,用于指定IP通信的源端和目的端IP地址,指导IP分片和重组,指定部分通信行为IP数据报的路由和转发
发生在除目标机器之外的所有主机和路由器上,它们决定数据报如何转发- 32位的IPv4地址已经耗尽,可使用128位IPv6地址
IP服务的特点
- IP协议为上层协议提供无状态、无连接、不可靠的服务
无状态
(stateless):IP通信双方不同步传输数据的状态,即所有IP数据报都是相互独立、无上下文关系- 缺点:无法处理乱序和重复的IP数据报,因为IP协议无法检测乱序和重复。(IP数据报头部也有提供标识字段来唯一标识一个IP数据报,但它仅用于处理IP数据报的分片和重组,不用于指定接收顺序)
- 优点:简单高效,不需为保持通信状态而分配资源,也不需每次传输都携带状态信息。(UDP和HTTP也是无状态,HTTP浏览器连续两次网页请求之间无关联)
无连接
(connectionless):IP通信双方都不维持对方的任何信息,即上层协议每次发送数据都必须指定对方的IP地址不可靠
:IP协议不能保证IP数据报准确地到达接收端,它只承诺尽最大努力。上层协议需实现数据确认、超时重传等机制以实现可靠传输- IP数据报发送失败的例子:
- 中转路由器根据IP数据报头部TTL字段发现它在网络上存活太久,会将其丢弃,并返回ICMP错误消息(超时错误)给发送端
- 接收端通过校验发现IP数据报不正确,会将其丢弃,并返回ICMP错误消息(IP头部参数错误)给发送端
- IP数据报发送失败的例子:
IPv4头部结构
IPv4头部结构
- IPv4的头部通常为20字节,除非含有可变长的选项。结构如图2.1
- 4位
版本号
指定IP协议版本:IPv4的版本号是4,其他IPv4的扩展(如SIP和PIP)有不同的版本号,头部结构也不同 - 4位
头部长度
是该头部的长度,单位是32bit(4字节),IP头部的最大长度是15*4=60字节 - 8位
服务类型
(Type Of Service,TOS)包括:- 3位优先权字段,现已被忽略
- 4位TOS字段,分别为:
最小延时
、最大吞吐量
、最高可靠性
,最小费用
。根据实际需要,至多能将其中一个置为1,如ssh和telnet需要最小延时,ftp需要最大吞吐量 - 1位保留字段,必须置0
- 16位
总长度
是整个IP数据报的长度,单位是字节,IP数据报的最大长度为65535字节,但长度超过MTU的会被分片传输 - 16位
标识
唯一地标识主机发送的每一个数据报,其初始值随机,每发送一个数据报就+1,分片时每一个分片的标识都相同 - 3位
标志
字段:- 第一位保留
- 第二位DF(Don’t Fragment)表示
禁止分片
,此时若IP数据报长度超过MTU将被丢弃并返回ICMP差错报文 - 第三位MF(More Fragment)表示
更多分片
,除数据报的最后一个分片外,其他分片都要将其置1
- 13位
分片偏移
是当前分片相对原始IP数据报开始处的偏移,实际偏移是该值*8(左移3位)得到的。因此除最后一个分片外,其他所有分片的数据部分长度必须是8的整数倍 - 8位
生存时间
(Time To Live,TTL)是数据报到达目的地之前允许经过的路由器跳数,每经过一个路由器该值就-1,减为0时路由器丢弃该数据报并向源端发送ICMP差错报文。TTL可防止数据报陷入路由循环 - 8位
协议
字段用于区分上层协议,在/etc/protocols
文件中定义所有上层协议的该字段值,该文件是RFC1700的子集。例如:ICMP是1,TCP是6,UDP是17 - 16位
头部校验和
由发送端填充,接收端对其使用CRC来校验IP数据报的头部 - 32位
源端IP地址
和目的端IP地址
用于标识发送端和接收端,在整个传递过程中一般不变 - 可变长的
选项
字段最多包含40字节(因为IP数据报头部最长是60字节,固定部分占用20字节),该字段使用不多,详细信息见RFC791:记录路由
用于告诉传播途经的所有路由器,将其IP地址填入IP头部的选项部分,这样可追踪数据报的传递路径时间戳
告诉每个路由器都将数据报被转发的时间填入IP头部的选项部分,这样可测量途径路由间传递的时间松散源路由选择
指定一个路由器IP列表,使得IP数据报传递过程必须经过这些路由器严格源路由选择
指定一个路由器IP列表,使得IP数据报传递过程只能经过这些路由器
使用tcpdump观察IPv4头部结构
- 在A机上使用telnet登陆到本机,并用tcpdump抓取第一个包
|
|
- tcpdump使用
-x
输出数据包的二进制码,该输出有60字节:前20字节是IP头部,后40字节是TCP头部,此处没有应用程序数据 - 该输出描述一个IP数据报,源端和目的端IP都是127.0.0.1,telnet服务器的端口号是23,Flag、seq、win、options都是TCP头部信息,length指出IP数据报携带的应用程序数据长度为0
- 前20字节的IP头部含义见表2.1,对照图2.1看。其中数据报标识和头部校验和这两项与我的输出不同
- 看出telnet选择使用最小延时服务,传输层默认用TCP协议
IP分片
- IP数据报长度超过帧的MTU时会被分片,它可能发生在发送端或中转路由,可能在传输中被多次分片,只有在目标机上才会完成分片的重组
- IP头部的数据报标识、标志、分片偏移这3个字段为分片重组提供信息
- IP数据报的每个分片都有自己的头部:
- 每个分片的
标识
相同 - 除最后一个分片外,
标志
中的MF
都被设置 - 每个分片的
分片偏移
不同 - 每个分片的
总长度
字段被设置为该分片的长度
- 每个分片的
- 以太网帧的MTU是1500字节,故携带的IP数据报的数据部分最多1480字节。
- 如图2.2是传递一个长未1481字节的ICMP报文时的IP分片:
- 对上图进行实验:
- 使用ping来传输ICMP报文,tcpdump抓取前两个包
|
|
- 命令:
- tcpdump使用-v输出更多内容(IP头部),使用icp指定只抓取ICMP报文
- ping使用-s指定每次发送的ICMP报文的数据部分是1473字节(ping使用的ICMP头部长为8,ICMP报文总长1481)
- 输出:
- 两个IP分片的标识值id都是36528,故是同一IP数据报的分片
- 第一个分片的偏移offset是0,第二个分片的偏移是1480(第一个分片的数据部分的长度)
- 第一个分片flags为[+]表明设置了MF标志,而第二个分片flag为[none]表明未设置标志位
- 两分片长度分别为1500和21
- IP层传递给数据链路层的数据可能是一个完整的IP数据报,也可能是一个分片,它们统称为
IP分组
(packet)
IP路由
- IP协议的核心之一是数据报的路由,即决定发送数据报到目标机器的路径
IP模块工作流程
- IP模块的工作流程如图2.3
- IP模块接收到来自链路层的数据报时,首先对头部做CRC校验
- 决定转发或内部处理:
- 若该数据报头部设置了源站选路(即松散/严格源路由选择),则将其传给数据报转发子模块
- 若该数据报的目的IP地址是本机或广播地址,即该数据报发送给本机,则根据头部的协议字段来分发给本机的上层应用(分用)
- 若该数据报不是发送给本机的,则也传给数据报转发子模块
数据报转发子模块
首先检测系统是否允许转发- 若不允许转发,则将该数据报丢弃
- 若允许转发,则对该数据报执行一些操作,并传给IP数据报输出子模块
IP路由
:决定IP数据报应发送至哪个下一跳路由或目标机器,以及经过哪个网卡发送。路由表
是实现IP路由的核心数据结构:- 路由表按照数据报的目标IP地址分类,同一类型的IP数据报将被发往相同的下一跳路由或目标机器
- IP路由策略:可通过路由协议或route命令调整路由表,使之适应新的网络拓扑结构
- IP输出队列中存放所有等待发送的IP数据报,包括本机发送的数据报和转发的数据报
路由机制
- 可使用
route
命令或netstat
命令查看路由表 - 使用route命令输出的路由表中每项包含8个字段,如表2.2
|
|
- 上述输出:
- 第一项的目的地址是default,即
默认路由
。flag中包含G说明下一跳是网关 - 第三项的目的地址是本地局域网,数据报不需要路由中转可直接发送到目标机器
- 第一项的目的地址是default,即
- IP路由机制的步骤:
- 查找路由表中与数据报目的IP完全匹配的主机的IP地址
- 查找路由表中与数据报目的IP具有相同
网络ID
的网络IP地址 - 选择默认路由,通常意味着下一跳路由是网关
路由表更新
- route命令可静态修改路由表
|
|
- 对于大型路由器,通常用BGP(Border Gateway Protocol,边际网关协议)、RIP(Routing Information Protocol,路由信息协议)、OSPF等协议来发现路径以自动地动态更新路由表
IP转发
- 不发送给本机的IP数据报交给数据转发子模块处理
- 路由器都能执行数据报的转发操作,但主机一般只发送/接收数据报,因为主机的内核参数
/proc/sys/net/ipv4/ip_forward
默认被设为0,可将其修改为1来让主机开启数据报转发功能 - 之前将B机设为A机的默认路由,但B机是主机,需开启转发功能才可让A机上网
|
|
- 对于允许IP数据报转发的系统(路由或主机),数据报转发子模块将对IP数据报执行操作:
- 检查头部TTL值,为0则丢弃
- 检查头部严格源路由选项,若该项被设置,则检测目标IP是否是本机,若不是则向发送端发送ICMP源站选路失败报文
- 若有必要,向源端发送ICMP重定向报文,告诉它更合理的下一跳路由
- 将TTL值减1
- 处理IP头部选项
- 若有必要,执行分片
重定向
- ICMP重定向报文也可用于更新路由表(图2.3)
ICMP重定向报文
- ICMP重定向报文如图2.4
- 在1.1节讨论过ICMP报文的格式有3个固定字段
- ICMP重定向报文的类型字段值是5,代码字段有4个可选值用于区分不同的重定向类型,其中主机重定向的代码值为1
- ICMP重定向报文的数据部分为接收方提供信息:
- 引起重定向的IP数据报的源端IP
- 应该使用的路由器的IP地址
- 接收主机根据这两个信息判断引起重定向的IP数据报应使用哪个路由来转发,并以此来更新路由表(通常是更新其缓存)
- 内核参数
/proc/sys/net/ipv4/conf/all/send_redirects
指定是否允许发送ICMP重定向报文,/proc/sys/net/ipv4/conf/all/accept_redirects
指定是否允许接收ICMP重定向报文 - 一般主机只能接收ICMP重定向报文,路由器只能发送ICMP重定向报文
主机重定向实例
- 将B机设为A机的网关,并在B机上开启数据转发功能,此时A机通过B机上网,在A机上ping百度
|
|
- 从ping的输出发现,B机给A机发送了ICMP重定向报文,告知A机通过192.168.1.1来访问目标机器。
- A机收到这个ICMP重定向报文后,更新自己的路由表缓存,使用新的路由方式发送后续数据报
- 如图2.5
IPv6头部结构
- IPv6解决了IPv4地址不够用的问题,还做了很大改进,例如:
- 增加多播和流的功能,精细控制多媒体内容的质量
- 引入自动配置功能,更方便管理局域网
- 增加了专门的网络安全
- IPv6的规范参见RFC2460
IPv6固定头部结构
- IPv6头部由40字节的
固定头部
和可变长的扩展头部
组成,如图2.6是固定头部 - 4位
版本号
指定IP协议的版本,IPv6的版本号是6 - 8位
通信类型
指定数据流的通信类型或优先级,类似IPv4的TOS - 20位
流标签
是IPv6新增字段,用于某些对连接的服务质量有特殊要求的通信,例如音视频实时传输 - 16位
净荷长度
是IPv6扩展头部和应用程序数据长度之和,不包括固定头部长度 - 8位
下一个头部
指出紧跟IPv6固定头部后的包头类型,如扩展头,或上层协议头部。它类似IPv4的协议字段 - 8位
跳数限制
类似IPv4的TTL - IPv6的地址是128位
- IPv4的地址是32位,用点分十进制分割为4组。而IPv6的地址用十六进制和
:
分割为8组,每组2字节 - 通常使用零压缩法简写IPv6地址,即省略连续的全0组。不过对一个IPv6地址只能省略一个全0组
- IPv4的地址是32位,用点分十进制分割为4组。而IPv6的地址用十六进制和
IPv6扩展头部
- 可变长扩展头部使IPv6可支持更多选项,且便于未来扩展
- 可变长扩展头部的长度可以是0,表示不使用扩展头部
- 一个IPv6数据报可包含多个扩展头部,每个扩展头部的类型由前一个头部(固定头部或扩展头部)中的下一个头部字段指定
- 可使用的扩展头部见表2.3
- IPv6协议并不是IPv4的扩展,它是完全独立的协议
- 以太网帧封装的IPv6数据报和IPv4数据报拥有不同的类型值,IPv4是0x800,IPv6是0x86dd