【Linux网络】IP协议
目录
- 什么是IP协议
- IP协议报头
- IP地址
- 网段划分
- 特殊的IP地址
- IP地址的数量限制
- 私有IP地址和公网IP地址
- 路由
- 数据链路层
- 以太网
- 以太网帧
- MAC地址
- MTU
- MTU和IP协议
- MTU和UDP协议
- MTU和TCP协议
- ARP协议
- ARP协议的作用
- ARP数据报的格式
- DHCP
- ARP欺骗
- DNS
- ICMP协议
- ping指令
- NAT
- NAPT
- NAT技术的缺陷
- 内网穿透
- 代理服务器
什么是IP协议
IP协议,全称互联网协议(Internet Protocol),是TCP/IP协议族中最核心的协议之一。它定义了数据如何在网络中进行寻址和路由,确保信息能够从源设备跨越多个网络到达目标设备。
在计算机网络中,传输层负责管理两个节点之间的数据传输,并准确交付给指定端口的进程。管理数据传输是为数据传输提供策略,但是负责决定数据如何传输的不是它,而是IP协议。
IP协议的本质是提供一种能力,将数据从主机A发送到主机B。而身为用户需要的是能以某种策略比如可靠地将数据从主机A发送到主机B的能力。而网络变化莫测,丢包是不可避免的,这对于IP协议也是一样,所以IP只能说尽可能发送,不能保证可靠,这时想要可靠的传输就得靠上层协议提供策略,比如TCP协议。那为什么不在网络层就解决可靠传输的问题呢?这个决策背后是计算机网络中一个非常重要的原则——端到端原则(End-to-End Principle)。该原则认为,某些功能(特别是像可靠性这种复杂功能)最好在通信路径的终点(即端系统)实现,而不是在中间的网络上实现。原因在于:
终点拥有全部信息:只有通信的最终双方才真正知道应用是否需要绝对的可靠(如文件传输),还是可以容忍部分丢失但要求低延迟(UDP)。
避免重复努力:即使在网络层保证了数据从A到B的路由器之间不丢失,但数据从B的传输层到B的应用层仍可能出错。因此,最终仍需要在端系统进行完整的可靠性检查。如果在网络层和传输层都做重复的可靠性保障,反而显得冗余和低效。
IP协议报头
4位版本:标识IP协议版本,IPv4值为4,确保通信双方版本一致。
4位首部长度:指示IP报头长度,单位是4字节,最小20字节,最大60字节。
8位服务类型:用于指定数据包所需的传输质量,如最小延迟或最大吞吐量。 3位优先权字段(已经弃用),4位TOS字段,和1位保留字段(必须置为0)。4位TOS分别表示:最小延时,最大吞吐量,最高可靠性,最小成本。这四者相互冲突,只能选择一个。对于ssh/telnet这样的应用程序,最小延时比较重要;对于ftp这样的程序,最大吞吐量比较重要。
16位总长度:IP数据报整体占多少个字节。最大65535字节。由此我们也能看出,IP报文通过固定长度的自描述字段让我们获得报头长度(没有选项20字节,有更长,最长60字节)和整体长度,从而将报头和有效载荷分离。
16位标识:唯一的标识主机发送的报文。如果IP报文在数据链路层被分片了,那么每一个片里面的这个id都是相同的。
3位标志:第一个标志位保留,留待未来使用,现在用不到。第二个标志位为1表示禁止分片,这时候如果报文长度超过MTU,IP模块就会丢弃报文;为0表示允许分片。第三个标志位为1时,表示该数据报不是最后一个分片,后面还有分片;值为 0时,表示这是最后一个分片,或者该数据报根本没有被分片。
13位片偏移:是分片相对于原始IP报文开始处的偏移。其实就是在表示当前分片在原报文中处在哪个位置。实际偏移的字节数是这个值 * 8 得到的。因此,除了最后一个报文之外,其他报文的长度必须是8的整数倍(否则报文就不连续了)。为什么就得是8字节呢?这完全是出于效率和可行性的权衡。IP报头的总长度是有限的,片偏移字段只分配到了13位的存储空间,用13位直接表示字节偏移,最大只能表示 2^13 −1=8191字节。乘以8后,最大可表示 8191×8=65528字节的偏移,足以覆盖IP数据报的最大长度(65535字节)。
8位生存时间:数据报到达目的地的最大报文跳数。一般是64。每次经过一个路由,TTL -= 1,一直减到0还没到达,那么就丢弃了。这个字段主要是用来防止出现路由循环。因为网络很大,所以难免出现错误,如果出现错误,因为报文有信号放大的机制(中继器、集线器、交换机等都有这个功能,数据转化成信号后年面衰弱,信号放大可以给它续命),没有生存时间的话会在网络中无限循环。
8位协议:指明数据部分承载的上层协议(如TCP为6,UDP为17)。这解决了如何将有效载荷交给上层的问题。
16位首部校验和: 使用CRC校验IP报头完整性,每经一个路由器需重新计算。
32位源IP地址和32位目标IP地址:表示发送端和接收端。
IP地址
IP地址是互联网协议地址的简称,它是网络设备在互联网或局域网中的唯一逻辑标识,类似于现实世界中的门牌号,确保了数据能够准确送达目的地。
IP地址分为IPv4地址和IPv6地址,IPv4地址32字节,IPv6地址64字节。尽管IPv4地址已经面临地址不足的问题,但是现在的主流还是IPv4,所以我们还是拿IPv4举例。IP地址是一串32位的二进制数字。为了便于人们使用,通常转换成点分十进制格式,即由四个0到255之间的十进制数组成,中间用点分隔,例如 192.168.1.1。
网段划分
每个IP地址都由两部分构成,即:网络号 + 主机号。网络号指明了设备所在的网络, 保证相互连接的两个网段具有不同的标识。主机号指明了是这一网段中的哪一台设备,同一网段的不同主机之间必须有不同的主机号。
不同的子网其实就是把网络号相同的主机放到一起。
如果在子网中新增一台主机, 则这台主机的网络号和这个子网的网络号一致,但是主机号必须不能和子网中的其他主机重复。
通过合理设置主机号和网络号,就可以保证在相互连接的网络中,每台主机的IP地址都不相同,但是如何分配IP地址又成了一个问题,现代路由器自带DHCP功能,能够自动的给子网内新增主机节点分配IP地址,避免了手动管理IP的不便,因此路由器也可以看做一个DHCP服务器。能自动分配,那么自动分配的策略是什么样的呢?
过去曾经提出一种划分网络号和主机号的方案,把所有IP 地址分为五类,如下图所示:
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地址都被浪费掉了。
这种有类别编址的方案的弊端被发现,所以人们又想出了新的方案,那就是CIDR(有类别编址)。有类别编制的关键就是子网掩码。子网掩码是一串32位的二进制数字,前面都是1,然后在某一位开始变为0,然后一直到结尾。为1的部分就是网络号部分,为0的部分就是主机号部分。这样就能区分网络号和主机号了,怎么做到的呢?将IP地址和子网掩码进行 “按位与” 操作,得到的结果就是网络号,因为按位与全为1才为1,所以和子网掩码的IP只有网络号部分也就是子网掩码前面的1的部分才会保持原来的样子,这就是网络号。子网掩码主要由网络管理员规划设定,之后由路由器(或更专业的DHCP服务器)自动完成分配。我们在Linux上使用指令ifconfig
指令就能看到网络相关的信息,
其中netmask就是子网掩码,每一台入网设备都有子网掩码。网络号和主机号的划分与这个IP地址是A类、B类还是C类无关。我们可以在有类别编址的基础之上再进行CIDR,设定子网掩码。
IP地址和子网掩码还有一种更简洁的表示方法,例如140.252.20.68/24,表示IP地址为140.252.20.68,子网掩码的高24位是1,也就是255.255.255.0。
路由器本质也是特定一个子网的主机,也要配置IP地址。路由器一定至少要连接两个子网(可以认为有多张网卡),路由器也就相当于同时在两个子网。路由器一般是一个子网的第一个设备,一般它的路由是:网络号.1。路由器的功能不只是IP报文的转发,它同时也有构建子网的功能。路由器是一台工作在网络层的设备,它接收到IP报文,会解包然后从数据链路层向上提交,到网络层后进行路由选择,然后再次向下提交,不断地完成这样的过程,最终到达目标主机,这样报文才会从网络层提交到传输层。
我们使用IP地址寻找主机的过程是什么样的呢?首先数据从主机发送到与之相连的路由器,路由器将其和子网掩码按位与,如果相同,就表示其在同一网段,那么就会查路由表,找到对应主机号的机器从而进行内网转发,这就是内网通信,如果不一样,那么路由就会向上提交给上级路由,再次进行相同的操作。IP地址通过网段划分将原本应该线性遍历的过程变成了一个个分支选择,就像树形结构一样,查找的本质是排除,这种方式让排除的效率变高了,所以网络的速度、效率也就变高了。
特殊的IP地址
将IP地址中的主机地址全部设为0,就成为了网络号,代表这个局域网。
将IP地址中的主机地址全部设为1,就成为了广播地址,用于给同一个链路中相互连接的所有主机发送数据包。
127.*的IP地址用于本机环回(loop back)测试,通常是127.0.0.1。
IP地址的数量限制
之前我们也说过,IPv4的位数是32位,IPv4的极限地址数量就是42亿9千万这样子,在过去的人们看来,计算机这么昂贵的设备不可能用得完这么多IP地址,所以这样设定,但是在如今的入网设备越来越多,IPv4地址已经严重不足了。另外,实际上,由于一些特殊的IP地址的存在,数量远不足43亿;另外IP地址并非是按照主机台数来配置的,而是每一个网卡都需要配置一个或多个IP地址。前面所说的CIDR在一定程度上缓解了IP地址不够用的问题(提高了利用率,减少了浪费,但是IP地址的绝对上限并没有增加),仍然不是很够用。
所以有以下三种方式来解决这个问题:
动态分配IP地址:只给接入网络的设备分配IP地址。因此同一个MAC地址的设备,每次接入互联网中,得到的IP地址不一定是相同的。
NAT技术。(后面详细说)
IPv6:IPv6并不是IPv4的简单升级版。这是互不相干的两个协议,彼此并不兼容;IPv6用16字节128位来表示一个IP地址;但是目前IPv6还没有普及。
IPv6的地址有128位,可以说是一个天文数字了,如果成功落实到全球的所有入网设备,这个问题就能在根源上解决,但是这样的措施谈何容易,IPv4是被写进操作系统中的协议,不可能轻易更改,而且现在的网络都基于IPv4发展了这么久,围绕着它发展了很多周边技术,不可能这么轻松的就改掉。现在我国的IPv6技术得益于国家政策,发展得很好,很多大公司虽然公网IP还是IPv4,但是内网采用的都是IPv6。有朝一日我国科技发展取得突破成果,而且是基于IPv6的,那么能驱使着IPv6普及了。
私有IP地址和公网IP地址
我们查看自己电脑的IP地址,或者有云服务器的也可以查看自己的云服务器
我们会发现,这些机器的IP好像都是192.168.X.X、172.18.X.X这样的,一个模子里刻出来的。其实这些根本就不是公网IP,而是私有IP,IP地址可以被硬性的划分成公网IP和私有IP,我们普通人日常生活中使用到的,基本上都是私有IP。
如果一个组织内部组建局域网,IP地址只用于局域网内的通信,而不直接连到Internet上,理论上使用任意的IP地址都可以,于是RFC1918规定了用于组建局域网的私有IP地址:
10.*,前8位是网络号,共16,777,216个地址 。
172.16.到172.31.,前12位是网络号,共1,048,576个地址 。
192.168.*,前16位是网络号,共65,536个地址。
包含在这个范围中的,都成为私有IP,其余的则称为全局IP(或公网IP)。
私有IP的出现就是为了解决IPv4资源枯竭的问题,同时也能提升内网安全性并简化本地网络管理。我们IP地址资源的分配是以国家为单位的,每个国家的运营商在其中扮演了重要角色,我国有三大运营商,他们进行交谈,分配到IP地址资源,同时也对我国的网络基础设施进行建设,建各种基站,通过各级路由对IP资源进行分配,最终光纤入户。但是IP资源是有限的,从国家到各省份,再到市县乡,我国拥有大量的人口,网络发展也很好,入网设备非常多,这么分一直到家家户户IP肯定不够用,所以到了一定程度后就会使用私有IP了,或者像一个大公司的服务器集群,也会用私有IP,大致的结构就是像上面这样,这样能节省地址,也方便管理。
私有IP当然只能在内网中使用,一旦到了公网上如果还使用私有IP,那么对方就无法找到你了,因为你的网络号是规定的私有IP网络号,根本没法找。不同的路由器,子网IP其实都是一样的(通常都是192.168.1.1)。 子网内的主机IP地址不能重复。但是子网之间的IP地址就可以重复了。路由器至少有两个IP地址,一个WAN口,一个LAN口,WAN又来对外,LAN口用来对内,WAN口的IP地址由它所在的网段的路由器分配,而LAN口则由自己或者说设定自己的管理员决定(一般是网段第一个地址或最后一个地址)。所以当你的网关(网关是计算机网络中连接不同网络、充当通信“关口”的关键节点或服务,其核心使命是解决网络差异,实现互通,一般就是路由器)路由器接收到你的IP报文时,就会在网络层替换掉它分配给你的你的私有IP,换成路由器的WAN口IP,当然不是说这个WAN口IP就是公网IP了,像上面这个WAN口还是私有IP,因为上级路由还是建的私网,但是没关系,因为这样你到了上级路由就还是会再次替换,这样迟早会变成公网IP的。这样对方收到报文后发回来的报文到了路由器了又该怎么往内网发呢?这个后面讲。这种不断替换私有IP的过程就是NAT技术(Network Address Translation,网络地址转换)。
所以,我们将之前讲的串起来,首先先是公网,然后不断地分,最后地址不够了就是私网,公网 + 私网共同构成了互联网。
路由
IP数据包的传输过程也和问路一样。当IP数据包,到达路由器时,路由器会先查看目的IP。路由器决定这个数据包是能直接发送给目标主机,还是需要发送给下一个路由器。依次反复,一直到达目标IP地址。那么如何判定当前这个数据包该发送到哪里呢?这个就依靠每个节点内部维护一个路由表。
我们可以在自己的电脑上使用指令
windows
route PRINT
Linux
route
查看内核路由表。
不止路由器有路由表,本地主机也有路由表,只要工作在网络层就有路由表。这里我们拿Linux的举例,当我们要决定一个报文的路由时,我们按照路由表逐个对照,将子网掩码和IP地址进行按位与,得出的结果和Destination(目标网络)进行比对,一致的话就再看Gateway(网关)。网关为0.0.0.0或*的话就表示表示目的设备与您的设备在同一个局域网(同一个网段)内,数据包不需要经过任何中间路由器(网关)转发,可以直接发送到目标设备。否则就表示目的设备在另一个不同的网络,需要借助网关(通常是路由器)才能到达,此时您的设备不会尝试直接联系最终目标,而是将数据包发送给这个指定的网关地址。此后,数据包如何到达最终目的地,将由网关及其后续网络设备的路由表决定。这就是所谓的“下一跳”转发。当一路匹配下来都不符合时,如果有default也就是默认路由时,可以看到它的目标网络是0.0.0.0,掩码是0.0.0.0,也就是谁来了都能匹配,这时就会转发给这个网关(通常是你的主路由器),由他决定下一跳。路由表的查询也不是乱来的,查询路由表时要遵守最长前缀匹配。当数据包的目的IP地址与路由表中多个条目都匹配时,设备会选择网络掩码最长(即网络前缀最具体、描述范围最小)的那条路由。也就是会选择更具体的那一个,像默认路由就是优先级的最低的,因为它没有前缀,描述最模糊,和谁都能匹配上。
Flags标记中U表示此条目有效,G表示此条目的下一跳是某个路由器地址,没有G标志的条目表示目的网络地址是与本机接口直接相连的网络,不必经路由器转发。Iface是发送接口。
数据链路层
数据链路层的作用是局域网通信,网络层的IP协议的作用是全局通信。网络层负责将数据从源主机跨网络传输到目标主机,并选择最佳路径;数据链路层负责在直接相连的两个节点(如你的电脑和路由器)之间传输数据。数据链路层定义了局域网内部通信的通用框架和职责,如帧封装、寻址、差错检测等。
实际上,报文并没有通过网络层发出去,而是交给了下一层也就是数据链路层。
以太网
数据链路层是理论模型与规则制定者(OSI参考模型中的一层),而以太网则是 具体技术与实践方案(一种广泛应用的局域网技术标准), 其标准不仅实现了数据链路层功能,还规定了物理层的连线、电子信号等内容。
以太网帧
以太网帧是以太网的数据格式
源地址和目的地址是指网卡的硬件地址(也叫MAC地址),长度是48位,是在网卡出厂时固化的。
帧协议类型字段有三种值,分别对应IP、ARP、RARP。
帧末尾是CRC校验码。
MAC帧如何解包?定长报头。如何向上交付?有类型。
MAC地址
MAC地址用来识别数据链路层中相连的节点。
长度为48位,及6个字节。一般用16进制数字加上冒号的形式来表示(例如:08:00:27:03:fb:19)。
在网卡出厂时就确定了,不能修改。mac地址通常是唯一的(虚拟机中的mac地址不是真实的mac地址,可能会冲突;也有些网卡支持用户配置mac地址)。
再网络层我们都说网络层要进行路由,决定下一跳,其本质就是不断地更改目标MAC地址,当到达一个路由器时,由数据链路层解包向上交付,到达网络层,然后网络层就会根据目标IP查找路由表,决定下一跳,再通过ARP协议确定下一跳的MAC地址,然后向下封装后发出。
MTU
局域网通信就是主机向局域网中的所有报文发送MAC帧,收到的主机将目标MAC地址和自己的进行比对,不符合的直接丢弃,符合的就进行处理向上交付。同一个局域网中同时只能有一个MAC帧在广播,如果有多个,就会发生数据碰撞,发生了碰撞就要进行碰撞避免算法,所以局域网在系统的角度可以看成是一个临界资源。
当然现在我们也能使用交换机来划分碰撞域减轻这种情况。
MTU(Maximum Transmission Unit,最大传输单元)是计算机网络中一个重要的概念。简单来说,MTU 是指网络能够传输的最大数据包大小,以字节为单位。以太网帧中的数据长度规定最小46字节,最大1500字节,ARP数据包的长度不够46字节,要在后面补填充位。最大值1500称为以太网的最大传输单元(MTU),不同的网络类型有不同的MTU。如果一个数据包从以太网路由到拨号链路上,数据包长度大于拨号链路的MTU了,则需要对数据包进行分片。不同的数据链路层标准的MTU是不同的。
为什么需要MTU呢?
首先是早期的以太网是共享链路,所以数据包过大就会导致占用链路时间过长,这就会导致碰撞的概率加大,而且如果传输出错,就要全部重发,数据包过长重发成本也高。而且不同类型的网络(如以太网、Wi-Fi、专线)其物理特性和协议不同,导致它们所能承载的数据帧最大长度自然不同。
MTU和IP协议
当一个数据包长度过大时,就要进行分片,但分片不是数据链路层的工作,而是网络层的工作,因为网络层管理着全局通信,视角更高,对MTU看得更全面,能应对不同的MTU,如果由数据链路层进行分片,那么每到一个节点就要组装一次向上交付,太麻烦。
所以为了面对切片的情况,IP协议的包头中有对应的字段来保证切片和组装。IP包头中的3位标志中第二位为0表示允许切片(默认允许),为1表示不允许,第三位为1表示后面还有小包,为0表示这是最后一个小包或者根本没有分片。16位标识则是唯一的标识主机发送的报文。如果IP报文在数据链路层被分片了,那么每一个片里面的这个id都是相同的。13位片偏移则是分片相对于原始IP报文开始处的偏移,用于组装分片用。
利用这三个字段,就能应对分片的各种情况了。首先如果IP报文的更多分片如果为1,那么就表示这是分片报文,且后面还有报文,如果是0,那么就可能是最后一个小包或直接就是一个报文,那么这时就根据片偏移,片偏移为0就表示它是第一个,然后有没有更多报文,那么它就没有分片,否则就有。当我们收齐分片之后,就按照片偏移进行组装,如果其中有小包丢失,根据偏移量和报文总长度也能算出来。
我们通过一个具体例子来理解分片过程。假设要发送一个总长度为 4000字节 的IP数据报(其中IP头部占20字节,所以数据部分为3980字节),它需要经过一个MTU为1500字节的网络。
确定单分片最大数据长度
MTU为1500字节,减去标准的20字节IP头部,每个分片最多能承载 1500 - 20 = 1480字节的数据。同时,为了满足“8字节对齐”的要求,实际可取的最大整数是1480字节。
计算分片数量
原始数据部分长3980字节。需要分成 3980 / 1480 ≈ 2.69片,因此需要 3 个分片来传输。
分片1数据长度:1480字节
分片2数据长度:1480字节
分片3数据长度:3980 - 1480 - 1480 = 1020字节
计算每个分片的片偏移
分片1:它是第一个分片,从原始数据的第0字节开始。所以片偏移 = 0 / 8 = 0。
分片2:在它之前,分片1已经传输了1480字节的数据。所以片偏移 = 1480 / 8 = 185。
分片3:在它之前,分片1和分片2共传输了 1480 + 1480 = 2960字节的数据。所以片偏移 = 2960 / 8 = 370。
当对方收到这些报文之后,根据16位标识知道他们属于同一个完整IP报文,然后根据是否有跟多后续报文判断结尾,之后根据偏移量进行组装。
MTU和UDP协议
一旦UDP携带的数据超过1472(1500 - 20(IP首部)- 8(UDP首部)), 那么就会在网络层分成多个IP数据报。
这多个IP数据报有任意一个丢失,都会引起接收端网络层重组失败。那么这就意味着,如果UDP数据报在网络层被分片,整个数据被丢失的概率就大大增加了。
MTU和TCP协议
数据链路层的发送能力有限,要求上层不要发送过大报文,不然就分片,分片本身也不好,报头有额外开销,也更容易丢失了。可是网络层也不能决定报文大小,对于UDP,报文多大就是多大,因为其面向数据包,一次发送就结束。然而TCP面向字节流,报文大小可以商量,所以TCP的数据包大小其实受限于MTU, 这也解释了为什么TCP不直接发一大块数据过去,而是一块块的小数据。TCP的单个数据报的最大消息长度,称为MSS(Max Segment Size)。MSS其实会在连接建立的三次握手中交换MSS信息,以较小的一方作为最终双方采用的MSS。最理想的情况下,MSS的值正好是在IP不会被分片处理的最大长度(这个长度仍然是受制于数据链路层的MTU))。双方在发送SYN的时候会在TCP头部写入自己能支持的MSS值。 MSS的值就是在TCP首部的40字节变长选项中(kind=2)。
MTU和MSS的关系是怎样的呢?MTU是整个MAC帧的大小上限,MSS则是TCP有效载荷的大小上限。
假如MTU是1500,在不考虑选项的情况下,MSS = MTU - 20(IP基础报头大小) - 20(TCP基础报头大小)= 1460字节。
ARP协议
ARP(地址解析协议)是网络通信中一个非常基础且关键的协议,简单来说,它的核心任务就是根据已知的IP地址,找出对应的MAC地址(物理地址)。需要需要强调的是,ARP不是一个单纯的数据链路层的协议,而是一个介于数据链路层和网络层之间的协议。
ARP协议的作用
我们之前都说网络层要根据目的IP进行路径选择,也就是查路由表,根据路由表决定下一跳,路由表只有下一跳的IP地址,没有MAC地址,而同一个局域网中的通信得有MAC地址才行(因为先由网卡接收,比对MAC地址,然后向上交付),那么我们该怎么知道同一个局域网中的指定IP地址的主机的MAC地址呢?靠ARP协议。
举个形象的例子:当我们走进一个全是陌生人的房间,大家相互都不认识,这时我想和张三交流,但是我不知道张三是谁,这时我可以在人群中大喊,张三是谁,我想和你说话,张三听到后就会过来和我谈话了。ARP协议就是这么个原理。一台局域网中的主机,可以不知道局域网中其他主机的MAC地址,但是接入了局域网,就有在局域网中发送数据的能力,也就是拥有”大喊“的能力,想知道同网段IP所对应的MAC地址,就可以大喊谁的IP是X.X.X.X,然后等待回应。
具体点来说就是:
首先,源主机通过查路由表,知道自己的下一跳对应的IP地址,这时它又不知道这个IP对应的MAC地址是多少,这时源主机发出ARP请求,询问”IP地址是192.168.0.1的主机的硬件地址是多少“,并将这个请求广播到本地网段(以太网帧首部的硬件地址填FF:FF:FF:FF:FF:FF表示广播)。
之后当目的主机收到广播的ARP请求,发现其中的IP地址与本机相符,则发送一个ARP应答数据包给源主机,将自己的硬件地址填写在应答包中;。
当然也不是每一次想知道局域网中指定IP对应的MAC地址都需要这么广播,每台主机都维护一个ARP缓存表,当我们之前用过一次ARP广播找过这个IP的MAC地址之后,就会缓存进这个ARP缓存表之中,缓存表中的表项有过期时间(一般为20分钟),如果20分钟内没有再次使用某个表项,则该表项失效,下次还要发ARP请求来获得目的主机的硬件地址。我们可以使用arp -a
i命令查看缓存表。
为什么缓存表要有过期时间呢?首先因为网络环境在不断变化,IP和MAC的映射不一定一直有效。其次是防止ARP欺骗攻击。最后也能清理系统资源。
ARP数据报的格式
首先是以太网帧的报头,没什么好说的,帧类型为0806。
硬件类型:2字节,指明网络类型,表示ARP报文在哪种物理网络上传输。1代表以太网,最为常用。
协议类型:2字节,指明要映射的网络层协议地址类型。0x0800代表IP协议(IPv4)。
硬件地址长度:1字节,指明MAC地址的长度(字节数)。6表示以太网MAC地址为6字节。
协议地址长度:1字节,指明网络层地址(如IP地址)的长度(字节数)。4表示IPv4地址为4字节。
操作类型(op):2字节,指明ARP报文的类型,这是区分请求与应答的关键字段。1:ARP请求(Request)2:ARP应答(Reply)。
发送端以太网地址:6字节,发送方设备的物理地址。
发送端IP地址:4字节,发送方设备的IP地址。
接收端以太网地址:6字节,接收方设备的物理地址。由于未知,通常填充为全0(00:00:00:00:00:00)或全F(广播地址)。
接收端IP地址:4字节,接收方设备的IP地址。
注意到源MAC地址、目的MAC地址在以太网首部和ARP请求中各出现一次,对于链路层为以太网的情况是多余的,但如果链路层是其它类型的网络则有可能是必要的。
我们发送的ARP请求应该是
这样的,目的MAC地址因为不知道,所以填全F表示广播,然后帧类型0806表示ARP协议。硬件类型1表示以太网,协议类型0x0800表示IPv4,硬件地址长度填6表示以太网地址长度为6字节,协议地址长度填4表示IP地址长度为4,op填1表示这是ARP请求,之后里面的目的MAC地址也填全F表示未知。
当该报文发送到局域网中时,局域网中的每一台机器都会收到,网卡接受到数据,由数据链路层解析,分离报头后发现目的MAC是全F,说明这是广播报文,类型0806表示这是ARP协议,所以就不会进行丢弃,而是交给上层ARP协议,当ARP协议拿到后,就会首先面对一个问题,这是ARP请求还是应答?局域网中ARP请求太常见了,请求和应答都有可能,所以当ARP协议拿到一个报文时,首先要做的就是看op,op是1就表示这是请求,那么这时就要目的IP是不是自己了,如果不是就在这一层丢弃,是那就先将发送端的目的IP和目的MAC更新到自己的ARP缓存表中,之后接收方会构建一个ARP应答,
对于应答来说,就不需要广播了,因为ARP请求中有对方的信息,直接按照那个发就行,其中将发送方的MAC地址和IP地址填入,op改成2就行了。
当局域网中的设备收到应答报文时,因为这时不是广播了,所以MAC地址不符合的在数据链路层就会丢弃,这样只有发送方才能成功接收,并解包交付给ARP协议,当拿到报文时,一样的,最开始先看op,op是2,表示这是ARP应答,这时就会核对目的IP和目的MAC,看看是不是自己的,是那就核对源IP,看看是不是自己要查询的,如果是那就将源IP和源MAC写进ARP缓存表中,之后继续之前要进行的MAC帧发送工作。
DHCP
一台主机刚接入一个局域网,可以说是啥啥都不知道,它要怎么获得IP地址呢?如果是能连接其他网段的局域网,默认网关是谁呢?首先我们当然可以自己静态配置,如果不想,可以靠DHCP(动态主机配置协议)。
当我们的主机接入有DHCP服务器的局域网时(现在的路由器基本都有这个功能,可以看作DHCP服务器),无线也好,有线也好。主机作为DHCP客户端,会向局域网内广播一个 DHCP发现报文,寻找可用的DHCP服务器。DHCP服务器收到广播后,会从预设的IP地址池中挑选一个未被占用的IP地址,连同子网掩码、默认网关、DNS服务器地址等信息,通过 DHCP提供报文 发给主机。主机通常会接受收到的第一个提供报文,并再次广播 DHCP请求报文,表明自己将使用该IP地址。最终,DHCP服务器回应一个 DHCP确认报文,正式将IP地址租给主机。至此,主机就获得了在网络中通信所需的身份信息。
当有了IP、子网掩码之后,同网段的主机IP对应的MAC地址,就都可以通过ARP协议解决了。
ARP欺骗
我们可以通过自己的IP和子网掩码,得到自己所在的网络号,然后拼接IP地址,ping所有的主机,通过这样的方式,得到所有主机的IP和MAC地址。这种方式可以更新自己的ARP缓存表,原因在于:如果收到多次同样的ARP应答,我会以最新的ARP应答中的IP和MAC的映射为准。这种方式无条件信任并接受收到的ARP响应报文,并据此更新本地的ARP缓存表,而不会去验证报文的真实性。我们可以依此对同局域网的主机展开攻击。
比如:当主机A想要知道IP为IP_B(举例用,表示主机B的IP)的主机的MAC地址,所以它发起了ARP请求,主机B也给予了应答。这时我作为主机C,收到了广播,到达ARP协议时即使与自身IP不和,我也不丢弃,根据这条报文的内容构建ARP应答,IP还是IP_B,但是MAC是MAC_C,将这条应答发给主机A,主机A 收到后,即使之前已经收到了主机B的正确应答,但还是会更新,将错误的IP - MAC映射更新上去,这样原本发给主机B的数据就全部被我拿到了。
如果这里替换的不是主机B,而是默认网关,那么主机A发给外网的数据全部会发给我,而我将其全部丢弃的话,主机A就会形成一种断网的效果,这就是断网攻击。
如果我不止向主机A发送欺骗报文,还向主机B发送欺骗报文,主机A的映射表中有IP_B - MAC_C,主机B的映射表中有IP_A - MAC_C。那么两台主机想要发送给对方的内容都会先发给我,我再原模原样进行转发,这样我就成为了双方之间的”中间人“,双方所有的通信流量都会流经攻击者,攻击者可以窃听通信内容(如账号、密码),甚至篡改传输的数据,而通信双方都意识不到我的存在,这就是中间人攻击。
当ARP欺骗成功后,我们可以劫持用户的网络会话,例如登录Cookie或Token,从而冒充用户身份登录其账户
。当然现代网络为了维护用户隐私、网络安全,很多都使用加密通信,如HTTPS。现在也有很多ARP防护功能的软件,这些软件可以监控本机的ARP缓存表,当发现异常变更(如网关MAC地址突然改变)时,会发出警报并阻止更新。
DNS
TCP/IP中使用IP地址和端口号来确定网络上的一台主机的一个程序,但是IP地址不方便记忆。于是人们发明了一种叫主机名的东西,是一个字符串,并且使用hosts文件来描述主机名和IP地址的关系。
最初,通过互连网信息中心(SRI-NIC)来管理这个hosts文件的:
如果一个新计算机要接入网络, 或者某个计算机IP变更,都需要到信息中心申请变更hosts文件。
其他计算机也需要定期下载更新新版本的hosts文件才能正确上网。
这样就太麻烦了,于是产生了DNS系统(域名系统):
一个组织的系统管理机构,维护系统内的每个主机的IP和主机名的对应关系。
如果新计算机接入网络,将这个信息注册到数据库中。
用户输入域名的时候,会自动查询DNS服务器,由DNS服务器检索数据库,得到对应的IP地址。
至今,我们的计算机上仍然保留了hosts文件。在域名解析的过程中仍然会优先查找hosts文件的内容。使用指令cat /etc/hosts
可以查看。
例如www.baidu.com,域名使用 . 连接
com:一级域名,表示这是一个企业域名。同级的还有 “net”(网络提供商),“org”(非盈利组织))等。
baidu:二级域名,公司名。
www:只是一种习惯用法,之前人们在使用域名时,往往命名成类似于ftp.xxx.xxx/www.xxx.xxx这样的格式,来表示主机支持的协议。
ICMP协议
ICMP(Internet Control Message Protocol,互联网控制消息协议)是TCP/IP协议族中一个非常重要的网络层协议,它负责在IP主机、路由器之间传递控制消息,用于报告通信过程中出现的各种问题,就像网络中的“信使”和“诊断医生”。
一个新搭建好的网络,往往需要先进行一个简单的测试,来验证网络是否畅通;但是IP协议并不提供可靠传输。如果丢包了,IP协议并不能通知传输层是否丢包以及丢包的原因。ICMP正是提供这种功能的协议,ICMP主要功能包括:
错误报告:当数据包无法送达目的地时,向源发送端报告错误原因。比如目标网络不可达、目标端口不可达。
网络诊断:测试主机是否在线、测量往返延迟、追踪数据包路径。比如使用 ping命令检查连通性,使用 tracert命令追踪路由。
流量控制:在网络拥塞时,通知发送方降低数据发送速率。比如发送“源抑制”报文。
路由优化:通知主机或路由器存在更优的数据转发路径。比如发送“重定向”报文。
ICMP也是基于IP协议工作的。但是它并不是传输层的功能。因此人们仍然把它归结为网络层协议;ICMP只能搭配IPv4使用。如果是IPv6的情况下。需要是用ICMPv6。
ping指令
ping命令是网络世界中最常用、最基础的诊断工具之一,它通过发送 ICMP (Internet Control Message Protocol) 回显请求数据包来测试网络连通性。
ping命令可以ping域名,也可以ping ip,都行:
ping命令不光能验证网络的连通性,同时也会统计响应时间和TTL(IP包中的Time To Live,生存周期)。
ping命令会先发送一个 ICMP Echo Request给对端;
对端接收到之后,会返回一个ICMP Echo Reply;
注意,此处ping的是域名或IP,而不是url!一个域名可以通过DNS解析成IP地址。ping指令是检测本地主机与目标主机(IP或域名)之间是否能够通信,不是两个进程之间的连通性,不需要端口。ping指令基于ICMP协议,是网络层的东西,输入指令后直接由ICMP协议构建报文发送,没有传输层、网络层的概念。
有道面试题会问telnet是23端口,ssh是22端口,那么ping是什么端口?ping没有端口,根本和端口不在一个层次。
NAT
我们在之前也说过,现在公网使用的还是IPv4技术的路由器,IPv4的路由器已经面临地址不足的问题,NAT(网络地址转换)技术是现在应对IP地址不足问题的主流解决方案,是现在路由器的重要功能。
网络地址转换(Network Address Translation, NAT) 是一种在IP数据包通过路由器或防火墙时,修改其源IP地址和目标IP地址的技术。通常,它还将同时修改TCP/UDP协议的源端口和/或目标端口。NAT的核心目的是实现私有网络地址与公有网络地址之间的映射和转换。
当公网IP被分配到一定程度时,就会面临IP不够用的情况,这时主流的做法就是搭建内网,使用规定的私有IP地址空间:
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
这些地址不能在公网上被路由,仅供内网IP使用。因为私有IP不能出现在公网上,那内网报文要进公网该怎么呢?这时NAT设备(通常是路由器)会对私有源IP进行替换,替换成路由器的WAN口IP,然后发出,WAN口IP也不一定是公网IP,但是只要不断过网关向外网发,最后就一定会被替换成公网IP。
NAPT
那么问题来了,报文成功发出,那么返回的应答该怎么返回到主机呢?源IP已经被替换,应答报文填的是路由器的WAN口公网IP,这样理论上只能到达路由器而已,如果这个路由器管理的子网只有一个主机那可以直接转给它,也就是一对一或多对多,但是这其实解决不了IP地址不够用的问题。
所以我们更进一步,使用IP + 端口来解决这个问题。NAPT,中文全称为网络地址端口转换,是NAT技术中最重要、应用最广泛的一种实现形式。它不仅在网络层(IP层)进行地址转换,更在传输层(TCP/UDP层)进行端口转换。
当我们对报文的私有IP和端口进行替换时,会将其写进NAPT维护的转换表中,该表记录了内部本地地址:端口与内部全局地址:端口的映射关系。因为IP在局域网中唯一,端口在主机中唯一,所以IP+ 端口可以唯一表示该局域网中的一个进程,下次再有对应IP + 端口的报文要出去时,可以直接用现成的。对于替换的WAN口IP + 端口也是有讲究的,不能全都用一样的端口,因为当应答报文回来时,得将其转发到对应的内网主机,所以映射的两边都会用来做Key,那么两边就都得在各自的那一边唯一,WAN口IP是不会变了,要变只能变端口,所以NAT设备会自动分配不同的端口给各个映射。
NAPT转换表中的映射数据也有设置倒计时,超时就会销毁。
所以NAPT其实就是将IP这个网络层的概念和传输层的端口组合,凭借实际主机开的端口不多从而将端口的剩余价值交给IP,缓解了IP地址不足的问题。
NAT技术的缺陷
由于NAT依赖这个转换表,所以有诸多限制;
无法从NAT外部向内部服务器建立连接;
装换表的生成和销毁都需要额外开销;
通信过程中一旦NAT设备异常,即使存在热备,所有的TCP连接也都会断开;
内网穿透
一个内网的机器想要被外网访问,该怎么做呢?我们可以使用内网穿透(又称NAT穿透)技术,它允许位于私有内网(如家庭或企业局域网,经过NAT/NAPT设备连接互联网)中的设备,被公网上的设备主动发现和连接。
内网穿透有很多解决方案:
(1) 端口转发 (Port Forwarding) - 静态配置
原理:在NAT路由器上手动配置一条固定的映射规则。明确指示:“所有发往本路由器公网IP的特定端口(如80端口)的流量,请直接转发给内网中特定设备的特定端口”。
优点:简单、稳定、高效。
缺点:
需要在路由器上设置,对普通用户有技术门槛。
运营商可能禁止用户访问路由器或使用公网IP(大局域网套娃)。
存在安全风险,对内网设备暴露过多。
适用场景:适合有固定公网IP且能操作路由器设置的用户,用于长期稳定的服务(如网站、服务器)。
(2)反向连接 (Reverse Connection) - 常见于商业软件
原理:
内网设备(客户端)主动地、持续地连接一个拥有公网IP的中介服务器。
当公网用户想访问内网设备时,它先连接到这个中介服务器。
中介服务器作为“传话员”,通过之前内网设备建立的连接通道,将公网用户的请求反向转发给内网设备。
优点:内网设备无需配置路由器,克服了NAT障碍。
缺点:所有流量都要经过中介服务器转发,该服务器成为带宽和性能的瓶颈,且通常需要付费。
适用场景:TeamViewer、向日葵、远程桌面、各种云服务的内网穿透功能。
(3)UDP打洞 (UDP Hole Punching) - P2P技术的核心
原理:这是一种更巧妙的方式,目标是让两个都位于内网的设备直接建立P2P连接,而不依赖中介服务器转发数据。
设备A和设备B都先连接到一台公网的协调服务器(STUN服务器)。
服务器记录下它们各自在NAT路由器上“映射”出的公网IP和端口(即它们对外通信的地址)。
服务器将设备B的公网地址信息告诉设备A,也将设备A的告诉设备B。
设备A和设备B同时向对方已知的公网地址发送数据包。
这些数据包会在对方的NAT路由器上“凿开一个洞”(即创建一条临时的映射规则)。由于规则是“由内向外”发起的,NAT允许返回的数据包通过,从而建立起直接连接。
优点:一旦建立成功,后续通信是点对点的,速度快,不耗费中介服务器流量。
缺点:技术复杂,对NAT设备类型有要求(无法穿透对称型NAT),成功率并非100%。
适用场景:视频通话(Skype、WebRTC早期版本)、P2P下载、在线游戏。
(4)中继转发 (Relaying) - 最终保底方案
原理:当打洞失败时(例如双方都是对称型NAT),协调服务器(TURN服务器)会退化为一个纯粹的流量中转站。设备A和B的所有数据都通过服务器进行转发。
优点:兼容性100%,总能保证连接。
缺点:效率最低,延迟高,带宽成本大。
适用场景:作为P2P连接的保底方案,确保通信在任何情况下都能进行。
注:
什么是STUN?
STUN (Session Traversal Utilities for NAT) 是一种网络协议,以及实现了该协议的服务器。它的核心功能是帮助位于NAT(通常是NAPT)之后的内网设备,发现自己被NAT分配的公网IP地址和端口是什么。对于P2P通信来说,双方需要知道对方的公网地址才能直接建立连接。STUN服务器就是来解决这个“我是谁?(在公网上)”的问题的。
什么是对称型NAT?
内网主机 (192.168.1.100:5000) 向每一个不同的外部目标地址(IP:Port),NAT都会给它分配一个全新的、独立的公网端口,也就是将目的IP也加入映射关系中作为Key的一部分。这样即使STUN服务器拿到了公网IP和端口,那也是映射的自己的IP和端口,别人拿到没用。
代理服务器
代理服务器(Proxy Server)是一种位于客户端(如您的浏览器)和目标服务器(如您要访问的网站)之间的中间服务器。它的核心功能是代表客户端向目标服务器发起请求,从而作为一道中间层处理网络交易。
代理服务器和NAT有点像,但其实是两个不同的概念:
从应用上讲,NAT设备是网络基础设备之一,解决的是IP不足的问题。代理服务器则是更贴近具体应用,比如通过代理服务器进行**,另外像迅游这样的游戏加速器,也是使用代理服务器。
从底层实现上讲,NAT是工作在网络层,直接对IP地址进行替换。代理服务器往往工作在应用层。
从使用范围上讲,NAT一般在局域网的出口部署,代理服务器可以在局域网做,也可以在广域网做,也可以跨网。
从部署位置上看,NAT一般集成在防火墙,路由器等硬件设备上,代理服务器则是一个软件程序,需要部署在服务器上。
代理服务器也分正向代理和反向代理。
正向代理用于请求的转发(例如借助代理绕过反爬虫)。正向代理最常见的就是我们的校园网,我们学生作为用户要使用校园网,首先要连上wifi,之后打开浏览器会弹出一个登录界面,登陆后网络流量才会通过。这当中其实就是学生先连上wifi也就是连上路由器,路由器和校园网服务器相连,所有连上路由器的主机发送的数据都会发送到校园网服务器,这时服务器就可以查看到这些报文信息,没有登录认证的会让其登录,对于某些服务的访问会被限制等。
反向代理往往作为一个缓存。比如公司内部有好多台主机配置了某个服务,公司想让这些主机均匀地接收请求,但是直接暴露IP和端口地方式往往做不到这点,暴露过多IP也会增加风险,所以这时可以设置一台主机作为代理服务器,其他主机与之相连,专门用于接收请求然后均匀转发到内网,这叫做负载均衡。反向代理一般人不咋用得到,都是这种特殊需求才会用到,比如上面所说的内网穿透的反向连接就是一种反向代理。