Linux 50 IP协议深度解析:从报头结构到子网划分与NAT

🔥个人主页: Milestone-里程碑

❄️个人专栏: <<力扣hot100>> <<C++>><<Linux>>

🌟心向往之行必能至

目录

一.IP协议

[1.1 IP协议的核心作用和构成](#1.1 IP协议的核心作用和构成)

[1.2 ip协议的报头](#1.2 ip协议的报头)

[1.3 网络划分(重点)](#1.3 网络划分(重点))

[1.3.1 为什么要子网划分](#1.3.1 为什么要子网划分)

[1.3.2 设置IP](#1.3.2 设置IP)

[1.3.2.1 解决IP不足](#1.3.2.1 解决IP不足)

[1.3.2.2 特殊的IP地址](#1.3.2.2 特殊的IP地址)

[1.4 IP地址的数量限制](#1.4 IP地址的数量限制)

1.4.1解决办法:私有IP和公有IP

[1.4.1.1 引入例子,加强理解](#1.4.1.1 引入例子,加强理解)

[1.4.1.2 再引入例子,更加详细,从市的局域网与公网](#1.4.1.2 再引入例子,更加详细,从市的局域网与公网)

1.4.1.3网络拓扑

[1.4.1.4 查看主机配置的IP](#1.4.1.4 查看主机配置的IP)

[1.5 报文分片](#1.5 报文分片)

[1.5.1 学习分片和组装](#1.5.1 学习分片和组装)

[1.5.2 细讲补充](#1.5.2 细讲补充)


一.IP协议

基本概念
主机: 配有IP地址, 也要进⾏路由控制的设备;
路由器: 即配有IP地址, ⼜能进⾏路由控制;(工作在网络层,但现在的路由器,应用层也可工作)
节点: 主机和路由器的统称

1.1 IP协议的核心作用和构成

IP协议:提供一种能力看,将数据报从A主机,跨网络,送到B主机

理解网络层和传输层

在数据传输过程中,网络层的IP有能力将数据传输成功

但有能力不代表一定能,此时就需要与传输层的TCP合作

这样,TCP/IP协议,才能把数据百分百可靠的,从A主机跨网络送到B主机

1.2 ip协议的报头

首先,我们要明确,IP协议的报头为固定长度,20字节,但这里4位头部长度,也才15啊,其实与TCP一样,基本单位是4个字节

0,15->4字节 0,60 然后 20/4->5->4+1->0100+0001->0101

8位服务类型
8位服务类型(Type Of Service): 3位优先权字段(已经弃⽤), 4位TOS字段, 和1位保留字段(必须置 为0). 4位TOS分别表⽰: 最⼩延时, 最⼤吞吐量, 最⾼可靠性, 最⼩成本. 这四者相互冲突, 只能选择 ⼀个. 对于ssh/telnet这样的应⽤程序, 最⼩延时⽐较重要; 对于ftp这样的程序, 最⼤吞吐量⽐较重要.
8位⽣存时间(
Time To Live, TTL): 数据报到达⽬的地的最⼤报⽂跳数. ⼀般是64. 每次经过⼀个路
由, TTL -= 1, ⼀直减到0还没到达, 那么就丢弃了. 这个字段主要是⽤来防⽌出现路由循环
如:
有时会出现报条一直在内部循环转发

16位首部检验和,使⽤CRC进⾏校验, 来鉴别头部是否损坏

与TCP所讲一样,是防止比特位翻转的

复制代码
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
	__u8	ihl:4,
		version:4;
#elif defined(__BIG_ENDIAN_BITFIELD)
	__u8	version:4,
		ihl:4;
#else
#error	"Please fix <asm/byteorder.h>"
#endif
	__u8	tos;
	__be16	tot_len;
	__be16	id;
	__be16	frag_off;
	__u8	ttl;
	__u8	protocol;
	__sum16	check;
	__be32	saddr;
	__be32	daddr;
	/*The options start here. */
};

4位版本号(version):
指定IP协议的版本, 对于IPv4来说, 就是4
• 8位协议: 表⽰上层协议的类型
• 32位源地址和32位⽬标地址: 表⽰发送端和接收端.
16位总⻓度(total length): IP数据报整体占多少个字节.
4位版本号(version): 指定IP协议的版本, 对于IPv4来说, 就是4

剩余的报头组成,在后续详细讲解

1.3 网络划分(重点)

IP地址分为两个部分, ⽹络号和主机号
• ⽹络号: 保证相互连接的两个⽹段具有不同的标识;
• 主机号: 同⼀⽹段内, 主机之间具有相同的⽹络号, 但是必须有不同的主机号


先建立共识,为什么我们发消息能够精准发送,本质上是网络本身是发展几十年的产物,与此同时,网络建设也是发展了几十年的(国内运营商建立基站,拉网线等)---网站是被设计的

引入例子加强理解,一所大学里,假设都分好了学院,而我们假设学号是:院号+专业+班级+学号

就如我们下面这张图,其中学院内的学生,除了该学院的学生会主席与其他院的学生会主席建立了校群,有向外通信的能力,其他的学生,都只能在自己这个院的局域网通信(此处我们简化了,其实应该还要班级等等联络人)

假设某天下雨,学号为01123的张三捡到了一个钱包,里面有许多贵重物品和一张学生卡(由于雨水,只能看到学号:03333)

而张三为了将这个钱包物归原主,可以在大学里一个一个地找,但效率太低,因此就应该通信

张三看学院号为03333,非自己学院号的01,自己不认识,不会通信,此时就采用了缺省值,交给院学生会主席01110,同时带上源IP地址(学号:01123)和目的IP地址(03333),而主席看到后,发现是材料学院的,就将这个转发1给材料学院的学生会主席,材料学院的学生会主席看到后,将带有目的IP和源IP和数据:钱包就交给了目的IP的人


与我们说过网络是被建设的,同样的,在我们没有上大学的时候,上面的学院也有了--->被学校已经建设好了(划分学院,带上唯一编号的过程:子网划分)

1.3.1 为什么要子网划分

未来查找目标主机,必须先查找目标网络

本质:

本质是淘汰其他网络,可以在全网中提高查找目标主机的效率

在上面的学校例子中,张三淘汰了自己学院的学生,院学生会主席淘汰了除材料学院的学生,材料的学生会主席淘汰了院内除目的学生的学生

同时,二分查找也是通过不断淘汰,提高效率


• 不同的⼦⽹其实就是把⽹络号相同的主机放到⼀起.
• 如果在⼦⽹中新增⼀台主机, 则这台主机的⽹络号和这个⼦⽹的⽹络号⼀致, 但是主机号必须不能
和⼦⽹中的其他主机重复.
如下面的主机A/B/C等都有网络标识,那么哪里来的呢?
其实是我们连网时,向路由器请求,路由器自动分配(DHCP)(断网可能会回收)

而我们的路由器,既要与内部设备通信,又要与外部通信,因此至少需要配置有两套IP

1.3.2 设置IP

IP是有限的,被各个国家的运营商抢占

为何要抢?构建自己的子网
⼿动管理⼦⽹内的IP, 是⼀个相当⿇烦的事情.
• 有⼀种技术叫做DHCP, 能够⾃动的给⼦⽹内新增主机节点分配IP地址, 避免了⼿动管理IP的不便.
• ⼀般的路由器都带有DHCP功能. 因此路由器也可以看做⼀个DHCP服务器.

IP=网络号+主机号
子网划分的本质:把32位比特位进行划分,确定有多少网络号


过去曾经提出⼀种划分⽹络号和主机号的⽅案, 把所有IP 地址分为五类(IPV4)

• A类 0.0.0.0到127.255.255.255
• B类 128.0.0.0到191.255.255.255
• C类 192.0.0.0到223.255.255.255
• D类 224.0.0.0到239.255.255.255
• E类 240.0.0.0到247.255.255.255

随着Internet的⻜速发展,这种划分⽅案的局限性很快显现出来,⼤多数组织都申请B类⽹络地址, 导致B 类地址很快就分配完了, ⽽A类却浪费了⼤量地址;
• 例如, 申请了⼀个B类地址, 理论上⼀个⼦⽹内能允许6万5千多个主机. A类地址的⼦⽹内的主机数 更多.
• 然⽽实际⽹络架设中, 不会存在⼀个⼦⽹内有这么多的情况. 因此⼤量的IP地址都被浪费掉了

1.3.2.1 解决IP不足

针对这种情况提出了新的划分⽅案, 称为CIDR(Classless Interdomain Routing)(⽆类别域间路由):
• 引⼊⼀个额外的⼦⽹掩码(subnet mask)来区分⽹络号和主机号;
• ⼦⽹掩码也是⼀个32位的正整数. 通常⽤⼀串 "0" 来结尾;
• 将IP地址和⼦⽹掩码进⾏ "按位与" 操作, 得到的结果就是⽹络号;
• ⽹络号和主机号的划分与这个IP地址是A类、B类还是C类⽆关;


举两个例子

子网掩码,即将IP与子网掩码进行&

通过子网掩码 的设置,原来68这部分的0100 0000+ 0100 = 0100 0100全变为了0

因此,子网存在的意义就是通过设置1的个数,重新设计网络号,使IP资源得到充分利用

上面这个 140.252.20.68/24后,子网地址范围,即这个子网最多连多少台主机

为256-1(子网后的为全0,表示局域网)-1(子网后全为1,表示广播地址(后续讲))

如果觉得上面的划分还是有点浪费,那么可以尝试下面的

上面的这个子网最多连14台主机

1.3.2.2 特殊的IP地址

• 将IP地址中的主机地址全部设为0, 就成为了⽹络号, 代表这个局域⽹;
• 将IP地址中的主机地址全部设为1, 就成为了⼴播地址, ⽤于给同⼀个链路中相互连接的所有主机发 送数据包;
• 1 27.*的IP地址⽤于本机环回(loop back)测试,通常是127.0.0.1

1.4 IP地址的数量限制

我们知道, IP地址(IPv4)是⼀个4字节32位的正整数. 那么⼀共只有 2的32次⽅ 个IP地址, ⼤概是43亿左 右. ⽽TCP/IP协议规定, 每个主机都需要有⼀个IP地址.
这意味着, ⼀共只有43亿台主机能接⼊⽹络么?
实际上, 由于⼀些特殊的IP地址的存在, 数量远不⾜43亿; 另外IP地址并⾮是按照主机台数来配置的, ⽽ 是每⼀个⽹卡都需要配置⼀个或多个IP地址.
CIDR在⼀定程度上缓解了IP地址不够⽤的问题(提⾼了利⽤率, 减少了浪费, 但是IP地址的绝对上限并没 有增加), 仍然不是很够⽤. 这时候有三种⽅式来解决:

• 动态分配IP地址: 只给接⼊⽹络的设备分配IP地址. 因此同⼀个MAC地址的设备, 每次接⼊互联⽹
中, 得到的IP地址不⼀定是相同的;
• NAT技术(后⾯会重点介绍);
• IPv6: IPv6并不是IPv4的简单升级版. 这是互不相⼲的两个协议, 彼此并不兼容; IPv6⽤16字节128
位来表⽰⼀个IP地址; 但是⽬前IPv6还没有普及;

1.4.1解决办法:私有IP和公有IP

如果⼀个组织内部组建局域⽹,IP地址只⽤于局域⽹内的通信,⽽不直接连到Internet上,理论上 使⽤任意 的IP地址都可以,但是RFC 1918规定了⽤于组建局域⽹的私有IP地址

10.*,前8位是⽹络号,共16,777,216个地址
• **172.16.***到172.31.*,前12位是⽹络号,共1,048,576个地址
192.168.*,前16位是⽹络号,共65,536个地址
包含在这个范围中的, 都成为私有IP, 其余的则称为全局IP(或公⽹IP);
网络宏观上被划分为:

公网:内网(子网,局域网)=1:n

但需要注意的是,我们普通人接入的都是内网,并且在网络通信的过程中,私有IP不可以出现在公网


1.4.1.1 引入例子,加强理解

假设上面刚开始发的

而发送主机发现122.开头的不在自己的局域网内,无法直接通信,于是就缺省路由,将它 转发给路由器,而路由器发现dst也不是自己所在的局域网,所以再缺省路由,发给他对应的路由器,同时通过NAT,将src地址匾额我i自己的QAN口IP

而接受到的路由器,发现122.*与自己处在同一个网络内,可以直接通信,因此直接进行发送,并将src替换为自己的WAIN口

目的路由器接受到后,再根据后续的主机地址发送给目的地,处理完再返回,而由于有公网的src IP,所以一定能返回路径的倒数第一个经过点,但返回到后,src与自己的WAIN口ip一样了,无法进行访问了,怎么办?

其实与前面使用NAT替换一样,会进行处理,此处后面详解


上面的过程中,我们发现堆src ip要一步一步进行替换,最多会替换到公网IP再完成任务后反向替换

试问: 如果 私有IP可以出现在公网上,那么我们局部的通信设备访问公网资源可以访问,但给我们返回应答时,该怎么处理? (私有IP只在子网为1,但如果我们不同的子网,相同的私有ip直接出现在公网,返回就不知返回给谁了)

欠费,敏感信息

如果我们绑定路由器的手机号欠费了,我们会发现自己无法使用wifi了,其实是我们发送的报文里,携带了话费余额,运营商看到欠费后,就不帮我们转发了

我们访问国外网站或者其他敏感信息的时候,会发现无法访问, 其实就是运营商检测到有敏感信息,不帮我们转发

公网的理解

每个国家都有公网IP进行组建自己的内网,而公网IP的多少,则是看网民的数量


小总结

1.上面通过NAT技术及私有IP不可出现在公网,就解决了IP地址不足的问题

2.每经过一个内网路由器,进行srcip的时候,替换成为当前路由器的wan口ip,(对外的)

3.上面的例子,我们也可以感受到,每个路由器,至少要配套两个IP

1.4.1.2 再引入例子,更加详细,从市的局域网与公网

一,国外俄罗斯的地址访问5.1.16.X,发给中国,一层一层替换src

而对应那些大公司,我们就可以将它们想像与市的服务器同级,而大厂的服务器一般在多个区域都会有部署


1.4.1.3网络拓扑

网络拓扑的结构非常复杂,这里我们把上面的"市",替换成为各个互联网公司,那么内网环境就是公司内网

1.4.1.4 查看主机配置的IP

linux : route

此时我们看到的default对应的ip就是缺省ip,当源地址要访问的ip在路由器未配置时,就转发给该ip

下面是两个例子

1.5 报文分片

我们前面的博客,可以看见,对应一个4000大小的滑动窗口还进行了分区,每个区的大小为1000,原因就是数据链路层的设定(后续详细讲解)

数据链路层:从上层接受下来的完整报文,大小不超过MTU,最大传送单元,一般是1500字节(但数据是1460字节,因为ip和tcp报头还要各占40字节),为什么?

并且数据链路层只通知,不分片,分片由你网络层完成,同样的,组装也由对端的网络层完成

举个例子,加强理解

你有1台10公斤的电脑,打算寄快递发给你的朋友,但快递公司说,他们最多一个快递寄3公斤,你为了寄出,只能进行拆分 分片,同样的,组装也是由你朋友收到快递后进行组装


结论一:网络通信的过程,如果过多分片,就会导致丢包率

但分片和组装不是主流,要减少,而主要收传输层传输有关

1.5.1 学习分片和组装

分片与组装主要用到上面表格中的第二行

• 16位标识(id): 唯⼀的标识主机发送的报⽂. 如果IP报⽂在数据链路层被分⽚了, 那么每⼀个⽚⾥⾯的这个id都是相同的. (不同报文,标识不同,相同报文,标识相同)
• 3位标志字段: 第⼀位保留(保留的意思是现在不⽤, 但是还没想好说不定以后要⽤到). 第⼆位置为1 表⽰禁⽌分⽚, 这时候如果报⽂⻓度超过MTU, IP模块就会丢弃报⽂. 第三位表⽰"更多分⽚", 如果 分⽚了的话, 最后⼀个分⽚置为0, 其他是1. 类似于⼀个结束标记.
• 13位分⽚偏移(framegament offset): 是分⽚相对于原始IP报⽂开始处的偏移. 其实就是在表⽰当 前分⽚在原报⽂中处在哪个位置. 实际偏移的字节数是这个值 8 得到的. 因此, 除了最后⼀个报⽂之外, 其他报⽂的⻓度必须是8的整数倍(否则报⽂就不连续了).


  1. 如何确定特定报文是否被分片?

1.更多分片是否是1,如果是1,就是分片

2.更多分片是否为0,如果是0且13位偏移量不为0,那就是分片

2.怎么确保自己把分片收全了

a.相同的标识的分片,聚合在一起!

b.怎么保证你收全了?

反过来想,怎么确定没有收全?

1.第一片丢失 即一个标识符的切片,没有偏移量为0的切片

2,中间片丢失

把收到的所有分片,按照片偏移量进行升序排序!

片偏移+自身报文的长度=下一个分片的片偏移数字

  1. 结尾丢失 没有更多分片为0的

所有组装则是与分片相反,不再赘述


1.5.2 细讲补充

1.如何尽可能确保不会分片?

在三次握手时,两端就会交换各自的数据链路层的MTU,进行比较,以最小的为上限

2.在网络转发的过程中,可能会遇到MTU更小的,此时就会再进行分片

相关推荐
Sincerelyplz1 分钟前
【AI会议纪要实践】mapReduce、RAG 与结构化输出
java·后端·agent
不想写代码的星星3 分钟前
从分支预测角度看 C++:为什么你的热循环慢得离谱?
c++
顺风尿一寸6 分钟前
深入Linux内核:mkdir系统调用的完整实现解析
linux
用户2367829801687 分钟前
Linux free 命令深度解析:从内存监控到 OOM 排查的完整指南
linux
过期动态8 分钟前
【LeetCode 热题 100】接雨水
java·数据结构·算法·leetcode·职场和发展
春日见9 分钟前
5分钟入门强化学习之动态规划算法与实现
大数据·人工智能·python·算法·机器学习·计算机视觉
DO_Community14 分钟前
为AI编程降本!OpenCode 原生支持 DigitalOcean 推理路由器
智能路由器·ai编程·claude
bug和崩溃我都要15 分钟前
Qt 封装 libmpv 全功能视频播放器开发指南
开发语言·qt·音视频
郝学胜-神的一滴20 分钟前
Qt 高级开发 018:复刻经典登录界面布局与窗口美化全解析
开发语言·c++·qt·程序人生·用户界面