每日学习之IPv4

IPv4协议
IP协议的任务包括以下几个部分:健康检查、防火墙、处理选项、分段/重组、接收、传输以及转发操作
IPv4报头
版本
报头长度:单位32位
服务类型
总长度:单位字节
识别:封包标识符
DF(不分段)
MF(还有其他片段)
片段偏移量:由IP协议的分段/重组功能使用
存活时间(TTL):代表iP封包若在规定时间内没有到达目的地则会被丢弃,多数使用默认值64
协议
报头校验和:确保IP报头在传输之后依然准确
源地址
目的地址
选项:可以为空,最大可达40字节
具体见下图:
微信截图_20250627135738
IP选项
大多数选项都很少被用到,只有在特定情况下会用到。选项可以分为单一字节选项和多字节选项两类。以下是两类选项的格式:
微信截图_20250627140319
无论是单一字节选项还是多字节选项,都有一个8位的type字段,这个字段可以进一步拆分为三个子字段
微信截图_20250627140526
多字节选项在type字段之后还有三个其他字段:Length(选项的长度,单位为8字节,包括type和length)、pointer(从选项开端起算的偏移量,初值为1)、option_data(处理此选项的中间主机必须存储数据的场所)
IPOPT_END选项为IP报头补白,使其对其4字节边界;IPOPT_NOOP选项用于填补选项之间的空白;source routing选项可以让传送者指定封包传至接收者所走的路径;Record Route选项用于请求发送方和目的方之间的路由器存储它们用于转发封包时所用的外出接口的IP地址。
封包的分段和重组
封包的最大尺寸为64KB,但是绝大部分接口类型都无法传递如此大尺寸的封包。因此需要将封包切成小段来进行传输,分段流程会建立一系列尺寸相同的片段,但是如果无法MTU刚好无法除尽封包大小,最后的片段就会比其他的要小:
微信截图_20250627142440
分段后的IP封包由目的主机重组,但是重组并非只在目的主机进行,有些必须查看完整IP封包的中间设备也会进行重组,例如防火墙和NAT路由器。
对IP封包进行分段和重组会对会对性能造成额外的负担,产生负面的延迟,因此视频会议系统这类对延迟很敏感的应用,会尽可能的避免分段。许多应用会通过以下两点来规避分段:1、使用路径MTU发现(Path MTU discovery)的功能,以发现可使用的最大封包尺寸。2、将MTU设定为相当安全的小值576。避免分段在改善响应时间上起到关键作用
IP封包在分组中涉及到以下字段:DF(不分段)、MF(更多片段,在分段时,每个片段的中的MF字段都会被设置为TRUE(最后一个片段除外)、片段偏移量(若偏移量为0则表示该片段为第一个片段,这很重要)、ID(一个封包的所有分段ID都是相同的,所以接受者能通过该字段得知哪些分段是归属于一个封包))
校验和
传输封包前,传送者会计算一个小而长度固定的字段,若在传输过程中,有数据变化,会导致计算出的校验和变化,前后对比,可以发现错误。在以下的情况中,会触发校验和的更新而非错误:递减TTL、封包调整(NAT)、IP选项的处理、分段。
封包的一般性处理
协议初始化
通过ip_init初始化:用dev_add_pack函数为IP封包注册处理程序,然后初始化路由子系统,再初始化用于管理iP端点的基础架构
与Netfilter的互动
防火墙再网络堆栈中的很多地方都有钩子函数,当封包或内核吻合条件时,封包会通过钩子函数。用户以iptables命令配置的过滤规则会决定是否丢弃封包。
与路由子系统的交互
IP层在传输或接受封包时,都会与路由表进行交互,通过ip_route_input函数决定封包命运,通过ip_route_output_flow函数返回下个跳点网关以及要使用的出口设备,通过dst_pmtu返回相关的PMTU(路径最大传输单元)。
IP转发
转发分割为两个函数ip_forward和ip_forward_finish,第二个函数会在第一个函数的尾端调用(只要Netfilter允许)。
转发的具体步骤如下:
1、处理IP选项
2、确定封包可以被转发
3、递减IP报头的TTL字段,当TTL字段变成0时,丢弃该封包
4、根据路径相关MTU,必要时处理分段工作
5、把封包传送至外出设备
如果封包没有被顺利转发,源主机会收到ICMP消息通知,来说明碰到的问题。但是即使封包被顺利转发,但是没有选择最佳路径,也会触发重导向事件,源主机会受到ICMP通知。
ICMP重导向
当主机系统被要求做某件另一台路由器比较适合的事情时,主机系统就会发出一条ICMP重导向消息。但是当封包作为源路由时,路由器会假设该路径有充足的理由,不会发送ICMP重导向消息。
传输
传输是指封包离开本地主机去往另一台主机。中央传递封包的函数是dst_output,下面讨论的函数都是替该函数将封包准备好。
用于分段处理的两组函数:
1、ip_queue_xmit:把IP报头加入已经创建好的数据片段中去
2、ip_push_pending_frames及相关函数:调用此函数不会考虑分段或者协助分段,出于提高效率的原因,L4协议会把封包中的数据直接往下传给IP层,但引入了处理的复杂性
3、ip_append_data:将传输请求暂存于缓存区,同时以透明方式产生一些最佳大小的数据片段,使得IP层稍后更易于处理分段
4、ip_build_and_send_pkt:由TCP使用,传输SYN ACK消息
5、ip_send_reply:由TCP使用,传输ACK和Reset消息
IP分段的两种方式
快速分段
当ip_fragment(处理两种分段方式的函数)接收了一个数据已经被分段的sk_buff,就会使用快速分段。
快速分段会从第一个IP片段中把报头拷贝到当前片段,然后对可能有所不同的IP报头字段做初始化,判断出该片段不是最后片段,就设定MF标志,从第一片段中把sk_buff的剩余字段拷贝到当前片段,最后用output函数来传输片段。
慢速分段
而慢速分段使用在所有其他不适用快速分段的场景,例如:被转发的封包;抵达dst_output前,尚未被分段的本地产生的流量;由于对缓冲区做健康检查使得快速分段法被关闭的情况
慢速分段的流程就是把IP封包分割成一些片段,而片段的尺寸由外出接口的MTU或者路径相关的MTU决定
IP重组
当封包到达最终目的地,而且必须传给上面的网络层时,就需要进行重组。高层接收到IP片段之后,会将其组织成一张hash表,每一个正在重组的IP封包,都会由一个ipq实例表示
微信截图_20250627164454
在如上图所示的hash表中可以存储大量的irq信息。每一个完整的封包都会有一个hash表,依次指向该封包的片段。
处理重组的主要函数时ip_defrag。该函数在每次调用时都会接收一个片段作为输入参数,然后尝试将该片段加入正确的封包中去,直至最后一个片段被正确加入到他的封包中去,该函数才会返回成功。
ip_defrag也涉及到很多辅助函数包括:ip_evictor(逐一删除不完整封包的ipq片段)、ip_find(找出和正在被处理的片段相关的封包)、ip_frag_queue(把指定片段插入同一个封包的ipq链表)、ip_frag_reasm(一旦所有片段都被接收,构建封包)
垃圾收集
内核为IP片段实现了两种垃圾收集方式:
1、系统内存使用限度:为防止IP重组子系统滥用内存,对该内存的使用强加限度,每当内存使用达到限度时,就会调用ip_evictor来释放一些内存
2、重组定时器:用于丢弃不完整封包的全部片段,以避免有完整的封包在hash表中呆的太久。
hash表重新组织
若hash函数尽可能均匀地散布在各个元素中,hash表就运行的好。如果存在大量冲突,会使IP片段群集在hash表的一些元素的链表中,致使性能下降,甚至容易遭受dos攻击,因此每隔10分钟(Linux系统默认)都会使用不同的hash函数来重新组织IP片段,使得hash表有足够的随机性,保证安全。

posted @ 2025-06-27 17:06  努力成为OM大师  阅读(60)  评论(0)    收藏  举报