全文概要
最近闲来无事,抄起本《Wireshark网络分析就是这么简单》想了解下数据包粒度(Packet-level)的网络测量及分析方法,书开篇提出一个面试题,与子网掩码相关,乍看心觉easy,咱好歹也是计算机专业学生,本科算是很认真学习过计算机网络课,且不说研究多么深入,但至少对于基础概念及重点问题,诸如OSI分层模型、TCP可靠传输机制、子网划分、路由算法甚至CSMA都如数家珍(毕竟好像教科书上科普重点就这么多…),小小的一个ping得通还是ping不通的问题,还能难倒我?
好吧,我承认,确实有困惑到…
然后一通想加一通做,再加一通找,于是就有了这篇文章…
大概…犯错及随之而来的自尊心作祟才是第一生产力。
基础概念
在本文对子网(Subnetwork)的相关机制进行阐释前,不管你是否有空或者有足够耐心坚持看完全文,在开头,我都觉得很有必要将会涉及到的基本概念先列出如下:
- IP地址,即网络层地址,以32位的IPv4地址为例,它通常分为网络地址(Network Address)和主机地址(Host Address)两部分;
IP地址分类,按照网络地址位数划分,一般可分作A、B、C、D四类,各类地址细节如下:
A类地址:用可变的7位(bit)来标识网络号,可变的24位标识主机号,最前面1位固定为“0”,即A类地址第一个字节的十进制数值范围介于1~126之间。注意,A类地址的第一个字节的十进制数值不能是0和127,127开头的IP地址保留给内部回送函数,专门用作诊断,如127.0.0.1是回环地址lo,用于回路测试;而0则表示该地址是本地宿主机,不能(无需)传送。
- A类地址通常为大型网络提供,全世界总共就只有126个A类网络,每个A类网络最多可以连接16777214(2^24 - 2, 主机位全0的IP地址用于标识本网络地址,主机位全1的IP地址用于标识广播地址,因此有两个IP地址不可用,故可表示的主机数量减2)台主机。
- A类地址的私有地址范围为:10.0.0.0 ~ 10.255.255.255。
B类地址:用可变的14位来标识网络号,可变的16位标识主机号,最前面2位固定为“10”,即B类地址第一个字节的十进制数值范围介于128~191之间,前两字节合在一起标识网络地址。
- B类地址适用于中等规模的网络,全世界大约有16000个B类网络,每个B类网络最多可以连接65534(2^16 - 2)台主机。
- B类地址的私有地址范围为:172.16.0.0 ~ 172.31.255.255。
C类地址:用可变的21位来标识网络号,可变的8位标识主机号,最前面3位固定为”110“,即C类地址第一个字节的十进制数值范围介于192~223之间,前三字节合在一起标识网络地址,最后一个字节用于标识主机地址。
- C类地址适用于校园网等小型网络,每个C类网络最多可以连接254台主机。
- C类地址的私有地址范围为:192.168.0.0 ~ 192.168.255.255。
D类地址:最前面4位固定为”1110“,它是一个专门的保留地址,并不指向特定的网络,目前这一类地址被用于多点广播,即多播(Multicast)中,多播地址用来一次性寻址一组主机,标识共享同一特殊协议的一组计算机。
E类地址:最前面5位固定为”11110”,为将来使用保留。
子网掩码(Subnet Mask),也是32位,用于标识一个IP地址的子网地址,计算子网号时,将计算机十进制的IP地址和子网掩码转换为二进制的形式,然后进行二进制按位与计算(全1则得1,不全1则得0),即得到子网地址。
还有一个,你同样需要知道的,由TCP/IP协议栈所规定的事实:
- 如果属于同一网段/子网,两个地址间的信息交换不通过或无需网关(如路由器)。
- 如果不属同一网段/子网,也就是子网号不同,两个地址的信息交换必须通过网关转发进行。
以及决定上述事实的原理:
- 以太网中,位于同一个网段/子网内的任意设备,可以两两ping通,仅在二层即数据链路层即可完成通信。在已知对方IP地址但不知道MAC地址情况下,可以通过广播ARP请求及获取ARP应答的方式构建新ARP表项,在通信发起方处维护对端IP地址到其MAC地址的映射,接着封装、发送目的MAC地址为对方MAC地址的以太网帧。
了解以上内容,“基本”可以回答那道令人困惑的面试题了。
就从Ping说起
面试题内容是这样的:
现有两台服务器A和B,具体配置信息如下表:
Server ID | IP Address | Subnet Mask | Default Gateway | MAC |
---|---|---|---|---|
Server A | 192.168.26.129 | 255.255.255.0 | 192.168.26.2 | 08:00:27:28:b9:11 |
Server B | 192.168.26.3 | 255.255.255.224 | 192.168.26.2 | 08:00:27:28:b9:22 |
默认网关IP:192.168.26.2/24,MAC地址:08:00:27:28:b9:33
问题描述如下:
B的子网掩码本来应该配成255.255.255.0,但不小心配成了255.255.255.224,那么A与B还能正常通信嘛?
- 如果不行,说明原因。
- 如果可以,请简述通信流程。
书上给出四个Plausible的答案,乍一看,真都好有道理:
- 版本一
- 答案:“A与B不能通信,因为…这都行的话,子网掩码还有什么用???”
- 评价:这位的反证法听上去让人无可质疑!
- 版本二
- 答案:“A与B可以通信,因为它们通过ARP广播获知对方MAC地址。”
- 评价:那子网掩码有什么用?上面的反证法刚好可用来反驳这位。
- 版本三
- 答案:“A与B可以通信,但所有包都要通过默认网关192.168.26.2转发。”
- 评价:请问这么复杂的结果你是怎么想到的?
- 版本四
- 答案:“A与B不能通信,因为ARP不能跨子网。”
- 评价:这个答案倒像是过了脑子的。
关于以上问题的事实:真相只有一个。
而事实有时候就很残酷:上面一个都不对。
解释说明题可与选择题不一样,后者结论对了找准选项就能拿满分,前者即使给出正确结论,但是荒谬无稽的解释则常常给阅卷人想要倒扣分的冲动…
按照正经答题的顺序,先告诉你正确答案:A与B可以通信。
接下来看看这个过程中发生了什么,以B ping A为例,至于为什么不是A ping B,请认真阅读下文内容,在之后我会解释原因。
要得出这个答案,我在Virtualbox上拿VM搭了个简单网络拓扑,两个VM分别作为Server A和Server B,第三个VM作为默认网关,并设置成允许转发:
echo 1 > /proc/sys/net/ipv4/ip_forward
得到的抓包结果如下图所示:
根据以上Wireshark的抓包结果,结合其中数据包出现的先后顺序,可将B ping A的通信流程作如下分析:
在B处,计算B的IP地址,即源IP地址,与A的IP地址,即目的IP地址,分别和B的子网掩码按位与的结果,即应用上文介绍的计算网络地址的唯一方法,发现:
B对应的网络地址为192.168.26.0,而A对应的网络地址为192.168.26.128,结果不同。
因此B会据此判断:
本机与目的主机A不在同一网段。
而不在同一网段的主机要进行通信,参考前文中关于跨网络通信的机制的内容,了解到B要想与A通信,必须经过默认网关(肯定与本机B在同一网段)的转发,故主机B会先把ICMP数据包发往默认网关192.168.26.2,我们知道要发送一个数据包,仅知道目的IP地址是不够的,真正在链路上传输时,目的主机的物理地址即MAC地址也是必须要一同封装在以太网帧中的,然而初始时并不知道默认网关的MAC地址。
ARP协议的作用正在于此:
B向本网段广播(ff:ff:ff:ff:ff:ff)一个ARP Request包,询问:“谁的IP地址是默认网关的地址,请把你的MAC地址回复给我”。
于是,本次通信的第一个数据包出现了!
- 默认网关接收到此ARP请求后检查目的IP发现就是自己,于是将自己的MAC封装在ARP Reply数据包中回复给主机B,这是第二个数据包。
- 主机B获知默认网关的MAC地址后,发送一个ICMP Request数据包给它,第三个数据包被发送,其实这个包本意是想发送给主机A,但中间需要默认网关帮忙中转一下,故此ICMP包的目的MAC地址为默认网关的MAC地址,但是目的IP地址仍为主机A的IP地址。
- 主机B迅速收到一个来自默认网关的ICMP Redirect数据包,即第四个数据包,意在告诉主机B:包我会转发的,你放心吧。但是至于包是不是真的被默认网关转发了,还不得而知,除非在默认网关处也抓到这个包。想到这里,不妨换个思路,根据结果接着往下分析。
- 然后我们在主机B上抓到了第五个数据包,居然又是个ARP请求包,根据源MAC地址显示,这个ARP请求来自主机A,那么它想干什么?包内容显示该请求想知道:谁的IP是192.168.26.3,也就是,谁是主机B?
- 在A处重复流程1中的IP地址与网络掩码的按位与运算,不过这次的网络掩码要用主机A的掩码,发现:A对应的网络地址为192.168.26.0,而B对应的网络地址竟然也是192.168.26.0!
- 你为什么会这么震惊?
- 你是不是发现了什么不得了的事儿?
- 没错,你已经知道了另一个事实:在A看来,本机与目的主机B在同一网段!从而A要主动向B发包的话,在知道其MAC地址的前提下,是可以直接发送而无需默认网关转发的。但好像又有不对劲的地方…容我反应一下…
- 你马上想到一个问题:A为什么会要给B发包?
- 我猜你问出这个问题的下一秒,已经知道了答案:当然是因为A已经收到了B的ping包,而A在想要回复B一个ICMP包时候发现自己并不知道主机B的MAC地址呀!
- 这间接证明了在流程3中,默认网关确实将B发送给它的那个目的IP地址为A的IP地址的ICMP包,正确地转发给了A。
- 至于第六个数据包,当然是主机B回复主机A的ARP请求的ARP Reply,将自己MAC地址告诉主机A,方便主机A响应此前自己的ping操作。
- 这就又证明了一件事儿:主机B在执行ARP回复时并不考虑子网,这不,虽然ARP请求在它看来,来自另一个子网的IP地址,但也照样回复。
- 这就又证明了一件事儿:主机B在执行ARP回复时并不考虑子网,这不,虽然ARP请求在它看来,来自另一个子网的IP地址,但也照样回复。
- 之后,主机B终于收到了来自A的ICMP Reply回包,即在抓到第七个相关数据包后,一次ping过程成功完成。
- 后来的过程中,主机A、B由于清楚地知道了对方的联系方式(各自以及默认网关的IP地址、MAC地址以及路由信息),此后的就没必要再发ARP包了,于是此后都是直接抓到双方由于ping产生ICMP数据包。
分析完这几个包,面试题的答案有了,原来通信流程是这样:B先把ping请求交给默认网关,默认网关再转发给A,而A收到请求后直接把ping回复给B,形成如下所示的三角环路:
让我们再回到之前的那个问题:为什么以B ping A为例,而不是A ping B呢?
其实答案已经一目了然:A ping B时,A通过子网掩码运算后发现B和自己在同一网段,广播ARP请求从来自主机B的ARP应答报文中获取其MAC地址,于是直接发送ICMP Request包给B。此后B进行回复,于是重复上述步骤1~4,随后默认网关将此ICMP Reply包转发至A,完成一次ping过程。
以上,算是完整解答了面试题的各种情况,但我们的目的绝不仅限于此,不是吗?
坚持积累的同时,也要及时的总结。
将零散的知识点经过总结后才能更容易整合到自己的技术体系中,会更有利于记忆和掌握,接下来我们好好掰扯掰扯子网这个东西。
子网掩码
功能
IP地址由网络号和主机号组成,网络号标识的是Internet(互联网)中的一个网段/子网,而主机号标识的子网中的某台主机。网际地址分解成两个域(Domain)之后带来了一个很明显的好处:
IP数据包从网际中的一个网络到达另一个网络时,路由器转发时选择路径可以基于网络而不是基于主机。在大型的网络中,这一点优势尤为突出,因为连接不同网络的路由表中只需存储网络信息,而不是主机信息,这样无疑简化了路由表,极大减轻了路由器的存储开销(Storage Overhead)。
看到这里,你大概会问,子网掩码在其中扮演了什么样的角色呢?
利用子网掩码就可以将一个IP地址分割为网络地址和主机地址两个域,具体作用体现在以下两方面:
- 屏蔽IP地址的一部分以区别网络号和主机号;
- 进一步划分网络,得到同一网络下的若干子网(Subnet)。
对应以上作用1,有如下IP地址组成二层结构等式:
- IP 地址 = 网络地址(Network Address) + 主机地址(Host Address)
以及,对应以上作用2,即如果进一步划分子网(Subnetting),IP地址变成三层结构:
- IP地址 = 网络地址(Network Address) + 子网地址(Subnet Address) + 主机地址(Host Address)
原理
那么子网掩码是如何实现上述功能的呢?
子网掩码包含32位,通过将网络位置为“1”,主机位置为“0”,完成网络地址与主机地址的分割功能,此时IP地址具有二层结构:
- IP地址 = 网络地址+主机地址
任何设备IP地址与其子网掩码按位与后的结果就可以得到其网络地址,具体到路由器上,每个需要其转发的数据包到达后,路由器使用将该包的目的IP地址与其对应的子网掩码按位与的方法,得出该目的IP地址所在网段,然后查询路由表,将数据包往匹配表项中指定的下一跳(Next Hop)进行转发。
此外,子网掩码还能帮助我们,将一个大型的IP网络,进一步细分为若干子网,这一过程叫作子网划分(Subnetting),通过向IP地址中原二层结构中的主机地址借用若干位作为子网位(Subnet ID),主机位减少位数,即可将一个较大的网络细分为 2^子网位数 个小型子网,此时IP地址具有三层结构:
- IP地址 = 网络地址 + 子网地址 +主机地址
并通过比较源IP及目的IP地址分别与本机子网掩码按位与后的结果是否相同,判断目的主机是否在局域网内(相同),或在远程网上(不同)。
无类别域间路由
无类别域间路由,即Classless InterDomain Routing,简称CIDR,该机制的引入是为了应对IPv4地址会被耗尽这个问题,注意,应对(Cope with),或者说缓解(Mitigate),但不是解决(Solve)。
IPv4地址总共32位,最多支持2^32=4294967296个IP地址,而地址分类机制,即将IP地址分为A、B、C等几个类别,每次划分时以8位作为递增步长,只支持8、16和24位的网络地址,而由于管理机构在为申请组织分配IP地址时,一般都是以网络为单位分配,即每次会将一整个网络的IP地址全部分配下发出去,这种分配机制十分不灵活,甚至会带来相当严重的浪费问题。
具体举例如下:
一个组织在申请网络地址时一次性最少也可以被分配到256个IP地址,此时对应C类地址,主机位数为8,假如这是家小公司,总共只需要15个独立IP,且无论短期还是长期都没有扩充机器数量的计划,这无疑就造成严重的地址浪费。
如果一个组织需要超过256个IP地址,假设1000个,那么管理机构就必须为其分配B类地址,而B类地址支持65536个独立IP地址,同样出现极大的地址浪费现象。
该组织需要超过65536个独立IP地址呢?为其分配A类地址,浪费更加不可想象!
出于安全等多方面的考虑,分配地址仍只能以网络为单位,故这种分配机制的不灵活性和浪费问题无法从根本上解决,CIDR就是提供了一种缓和机制:划分IP地址时以1位作为递增步长,这样不仅支持8、16、24三种网络位数,网络位数位小于32位的任意位数都为合法IP地址,这时的网络位数还是由子网掩码来确定。
下图展示了将子网掩码应用于A、B、C等类别(Classful)网络,以及无类别(Classless)网络的情况:
当然,CIDR机制仅仅只是缓和了IPv4地址消耗过快的事实,使得IP地址能够以一种更加高校的方式被管理结构分配给网络服务提供商(Internet Service Provider,ISP)和用户,但是正如上文所说,随着互联网设备和用户规模与日俱增,这“治标不治本”。到目前为止,要想真正解决网络地址短缺的问题,及早普及在1993年引入的IPv6协议才是终极方法,在IPv6协议下,网络地址为IPv6地址,包含128位(bit),支持的独立地址数量达到了2^128这一根本无法企及的天文数字。
参考资源
[1] What is a Subnet Mask
[2]如何理解子网掩码中的“子网”
[3]网络基本功:细说IP地址与子网