ip 协议相关
ip 协议属于 ip/tcp 协议族,它为上层协议(tcp/udp/icmp等)提供无状态,无连接,不可靠的服务
ipv4 头部结构
- ipv4 头部长度通常为 20 字节,最多为 60 字节(含有 40 字节的选项部分)
- 4 位版本号(version)指 ip 协议的版本。ipv4 的版本号值为 4,其他 ipv4 协议的扩展版本(如 sip 协议和 pip 协议)具有不同的版本号
- 4 位头部长度(header length)标识该 ip 头部有多少个 32bit。因为 4 最大能表示 15,所以 ip 头部最长是 60 字节
- 8 位服务类型(type of service, tos)包括一个 3 位的优先权字段(现在已经被忽略), 4 位的 tos 字段和一位保留字段(必须置 0)。4 位的 tos 字段分别表示:最小时延,最大吞吐量,最高可靠性和最小费用。其中最多有一个能置为 1,应用程序应根据实际需求来设置它。如像 ssh 和 telnet 这样的登录程序需要的是最小时延的服务,而文件传输则需要最大吞吐量的服务
- 16 位总长度(total length)是指整个 ip 数据报的长度,以字节为单位,因此 ip数据报的最大长度为 65535(2^16-1)字节。但由于 mtu 的限制,长度超过 mtu 的数据报都将被分片传输,所以实际传输的 ip 数据报的长度都远小于 65535字节
- 3 位标志字段的第一位保留。第二位(don’t frament, df)表 “禁止分片”。若该位设置为 1,ip 模块将不对数据报进行分片。在这种情况下,如果 ip 数据报文长度超过 mtu,ip 模块将丢弃该数据报并返回一个 icmp 差错报文。第三位(more fragment, mf)表 “更多分片”。除了数据报最后一个分片外,其他分片都需将其置 1
- 13 位分片偏移(fragmentation offset)是分片相对原始 ip 数据报数据部分开始处的偏移。实际的偏移值是该值左移 3 位后得到的。因此除最后一个分片外,每个 ip 分片的数据部分长度都必须是 8 的倍数,不然后面的 ip 报文取不到合适的偏移值
- 8 位生存时间(time to live, ttl)是数据报到达目的地之前允许经过的路由器跳数。ttl 值被发送端设置(常见值是 64)。数据报在转发过程中每经过一个路由,该值就被路由器减一。当 ttl 值减为 0 时,路由器将丢弃该报文,并向源端发送一个 icmp 差错报文。ttl 值可以防止数据报陷入路由循环
- 8 位协议(protocol)用来区分上层协议。/etc/protocols 文件定义了所有上层协议对应的 protocol 字段的数值。其中 icmp 为 1, tcp 是 6, udp 是 17
- 16 位头部校验和(header checksum) 由发送端填充,接收端对其使用 crc 算法以检验 ip 数据报头部(仅检验头部)在传输过程中是否损坏
- 32 位的源端 ip 地址和目的端 ip 地址用来标识数据报的发送端和接收端
- 选项字段(option)是可变长的可选信息,最多包含 40 字节。可用的 ip 选项包括:
- 记录路由(record route),告诉数据报途径的所有路由器都将自己的 ip 地址填入 ip 头部的选项部分,用于跟踪数据报的传递路径
- 时间戳(timestamp),告诉每个路由器都将数据报被转发的时间填入 ip 头部选项部分。可以用于测量途径路由之间数据报传输时间
- 松散源路由选择(loose source routing)指定一个路由器 ip 地址列表,数据报发送过程中必须经过其中所有路由器
- 严格源路由选择(stict source routing)和松散源路由类似,不过数据报只能经过被指定的路由器
ip route
ip 模块工作流程
从右往左分析上图。当 ip 模块接受到来自数据链路层的 ip 数据报时,它首先对该数据报的头部做 crc 校验,确认无误后接着分析其头部的具体信息。
若该 ip 数据报的头部设置了源站路由选项(选项中的松散源路由选择或严格源路由选择),则 ip 模块调用数据报转发子模块来处理该数据报。如果该 ip 数据报的头部中目标 ip 为本机的 ip,或者是广播地址,既该数据报是发送给本机的,则 ip 模块就根据数据报头部中的协议字段来决定将其发给哪个上层应用。若 ip 模块发现该报文不是发送给本机的,则也调用数据报转发子模块来处理该数据报
数据报到达数据报转发子模块时,数据报子模块将首先检测系统是否允许转发,如果不允许,ip 模块就将数据报丢弃。如果允许,数据报转发子模块将对该数据报进行一些操作,然后将其交给 ip 数据报输出子模块
ip 数据报应该发送到哪个下一跳路由,以及经过哪个网卡来发送,就是 ip 路由的过程,即 “计算下一跳子模块”。ip 模块实现数据报路由的核心数据结构是路由表。这个表按照数据报目标 ip 地址分类,同一类型的 ip 数据报将被发往相同的下一跳路由
ip 输出队列中存放的是等待发送的 ip 数据报,其中除了需要转发的 ip 数据报外,还包括封装了本机上层数据(icmp 报文、tcp 报文段和 udp 数据报)的 ip 数据报
上图中的虚线箭头显示了路由表更新的过程。这一过程是指通过路由协议或者 route 命令调整路由表,使之更适应最新的网络拓扑结构,称为 ip 路由策略
在数据报转发子模块中会执行如下操作
- 检查数据报头部的 ttl 值,若 ttl 值为 0 则丢弃该数据报
- 查看数据报头部的严格源路由选择选项。若该选项被设置,则检测数据报目标 ip 地址是否是本机的某个 ip。若不是则发送一个 icmp 源站选路失败报文给发送端
- 如果有必要,给源端发送一个 icmp 重定向报文,告诉源站更合理的下一跳路由器
- 将 ttl 减一
- 处理 ip 头部选项
- 如果有必要,则执行 ip 分片操作
路由机制
通过 toute 命令可以获取当前机器上的路由表
该路由表包含三项,每项都有 8 个字段,各个字段解释如下表
路由 ip 匹配规则
- 查找路由表中和数据报的目标 ip 地址完全匹配的主机 ip 地址。如果找到,使用该路由项,否则转到步骤哦 2
- 查找路由表中和数据报牧宝 ip 地址具有相同网络号的 ip 地址。如果找到,使用该项路由,否则转到步骤 3
- 选择默认路由项,这通常意味这数据报的下一跳路由是网关
ipv6 头部结构
ipv6 头部由 40 字节的固定头部和可变长的扩展头部组成
ipv6 固定头部结构
- 4 位版本号(version)指定 ip 协议的版本。ipv6 的版本号值是 6
- 8 位通信类型(traffic class)指示数据流通信类型或优先级,和 ipv4 的 tos 类似
- 20 位流标签(flow label)是 ipv6 新增加的字段,用于某些对连接的服务质量有特殊要求的通信,如音频或视频等实时数据传输
- 16 位净荷长度(payload length)指的是 ipv6 扩展头部和应用程序数据长度之和,不包括固定头部长度
- 8 位下一个包头(next header)指出紧跟 ipv6 固定头部后的包头类型,如扩展头(如果有的话)或者某个上层协议头(如tcp, upd 或 icmp)。类似于 ipv4 头部中的协议字段,且相同的取值具有相同的含义
- 8 位跳数限制(hop limit)和 ipv4 中的 ttl 含义相同
- 128 位源 ip 和目标 ip。用十六进制的字符串表示,如 “FE80:0000:0000:0000:1234:5678:0000:0012”。用 “:” 分为 8 组,每组两个字节。另外,对于连续的、全 0 的组可以省略简写,上例的 ip 可以简写为 “FE80::1234:5678:0000:0012”。需要注意的是,零压缩法对一个 ipv6 地址只能用一次,否则无法计算 “::” 省略了多少个全 0 组
ipv6 扩展头部
ipv6 扩展头部 扩展头部的长度可以是 0,表示没有任何扩展头部。一个数据报也可以包含多个扩展头部,每个扩展头部的类型由前一个头部(固定头部或扩展头部)的下一个报头字段指定。目前支持下列扩展头部