前言
问题是由这样的一个题目引出的,朱皓同学在我们部门8月31日的每日一题中给大家留下了这样一道题目
我们暂不关心这个网络拓扑是否合理,只是考虑技术方面的问题。
这个题是关于IP报文的转发问题,也许很多同学都知道答案了。不过相信会对很多新同学很有帮助。希望大家根据自己的答案把IP报文转发的过程也分析一下,为什么所答的方案可行?
图1 组网图
这个网络分为4个区域,研发部门的终端区域和服务器区域,财务部门的终端区域和服务器区域。所有的主机都通过3个HUB连接到一个路由器,并且将自己的网关指向路由器连接本网络的接口地址。路由器做了ACL控制对各种访问进行控制情况如下:研发区域和财务区域无法互相访问
某一天,我们需要完成这样一个任务,需要让研发服务器区域内的服务器A和财务服务器区域内的服务器B互通。但有两个限制条件
1.不能修改路由器的配置。
2.两个服务器都在24小时不间断的提供服务,不可让服务中断。
我们在这个问题上展开了激烈的讨论,由此我也想到了前两天林皓,王刚同学和我一起做的一个小试验,和这个问题的结果不谋而合,所以想总结一点自己的想法,权当抛砖引玉,希望高手来指正。
IP报文转发
摘 要:本文记录了一次大家对于一个网络问题的讨论,以及一次自己亲手做的一次试验,并记录了和这个问题相关的转发过程中的细节。希望能够为以后的讨论提供参考的依据。
由于研发部门的服务器区域和财务部门的服务器区域是通过hub连接的,也就是说,两边服务器上(比如A)发出的任何一条报文都会被发送到其他所有的机器上(其中当然也包括B了),当B的链路层从物理层接到了这条报文以后,会先检验MAC地址,如果不是我的,就置之不理,不再向上层提交,对于网络层以及更高的层次而言,它什么也没见到,所以这条报文看起来就是没有发送到。
既然A的报文能够顺利的到达B的网卡上,A和B之间的通讯似乎就没有什么难度,可是为什么A和B之间无法通信呢?原来,因为AB分属两个不同的网段,AB之间的所谓能够到达只是在物理链接上的可以到达,而对于上层而言,它们对于对方的情况一无所知,当然就更谈不上通信了。就好比A和B是两个互相不认识的人,对于A而言,从B那里收到的报文就好像路上一个陌生人投来的微笑一样,跟自己没有关系,而被忽略掉。对于B而言,情况也没有什么不一样。
那么A和B之间为什么没法进行沟通呢?因为A和B不在同一个网段上,A通过路由查询,发现只有把报文发送给自己的默认网关,而在Router这里,由于有ACL隔断,报文到了这里,好像遇到了一块游人止步的牌子,不再向后传递了。反之亦然。
其实说来说去就是想让B在能够把A发送给它的报文从一大堆报文中认出来,知道是发给自己的,然后向上层提交。在这里,我们考虑最多的也就是绕过Router,让B的IP层能够收到带着B的IP地址的报文,并向上提交。只要报文能够通过B的第二层和第三层,基本上就可以认定报文被送达,AB之间能够进行通信了。
从这个角度出发,我们开始了下面的讨论。
首先是李丹同学想到了缩短掩码的方法,将AB两个服务器的掩码缩短一位,变成24位,这样的话,两个服务器就处于同一网段了,用hub连接的同一网段上的主机是可以互相通信的。
但是,如果要修改掩码的话,我们必须要中断服务。
所以这个问题不符合要求,只好pass掉了。
林皓同学马上提出了这样的解决方案,在A、B上各自配置下一跳地址为对方主机,32位掩码的静态路由,按照最长匹配原则,比网关优先,因此发出的IP报文目的MAC和IP都是对方。
但是,这个方法也马上遭到了朱皓同学的强烈批评,虽然A能通过路由查找的精确匹配找到了32位主机路由为192.168.10.128/25,下一跳为 192.168.10.200,但是192.168.10.200不是自己的直连网段,于是就出现问题。这个过程到不了ARP请求,所以虽然连在一个HUB上,也是不通的。
所以这个想法也只好pass掉。
用这个方法A不会发送ARP请求,也就无法获得B的MAC地址,自然无法继续后面的通信活动了。
在两台服务器上手工配置网关的ARP为广播MAC,这样A在发送报文的时候,会将报文的MAC地址设为FFFFFFFFFFFF,hub上连接的所有设备都能接收到了(当然,这其中也包括了B),然后大家就都往IP层提交,其他的主机在第三层将报文丢掉,只有B发现这条报文是发给自己的,然后向上提交,这样AB之间就可以互相通信了。
但是,这个方法,会使所有A和B所发出来(去router)的报文都在hub连接的局域网内广播,严重的降低了两边系统的效率,所以这个方法基本上不在考虑范围之内。
这个方法是杜祥宇老师提出的,我在一开始的讨论中也提到了一下,不过马上被人批判了一通,所以也没有继续发展,权当作是一种思维方式。
巴麒同学提出了,在服务器上配置网卡的第二地址的方法,让研发服务器和财务服务器在一个网段上,绕过路由,直接通过hub通信。
在Win2000 Server下,可以在TCP/IP属性的高级属性里设置多个IP地址,把两边的服务器放在一个新的子网里,它们之间就可以互相通信了。
这个方法很好,操作起来也简单,是一个成功的方法。
在A上面配置一条主机路由,并且将下一跳指向自己。这样A会发出目标IP为B的ARP请求,B会以自己的MAC进行应答。这样做在Windows系统下可以实现,但是不同系统的ARP实现略有不同,有些系统(比如我司的路由器)不会对非本网段的A发出的ARP请求做回应,所以需要在增加了静态路由的前提下再增加静态ARP,指出B的MAC地址。这样做似乎也能达到目的。
但是在有些情况下,比如在策略严格的系统中,不允许配置一个ARP指向一个非接口直连的IP地址,这样一来,这种做法就无法实现了,所以我们把这种方法也淘汰了。
在我司的路由器在实现上,会对于收到的ARP请求做检查。路由器发现ARP请求的源IP和自己不在同一个网段上,不会进行ARP应答。
[PBX-P-GRE]
Routing Tables:
192.168.31.0/24 Direct 0 0 192.168.31.2 Ethernet0
192.168.31.2/32 Direct 0 0 127.0.0.1 LoopBack0
192.168.33.1/32 Static 60 0 192.168.31.2 Ethernet0
从192.168.33.1送过来的ARP请求
ARP: Received Arp Request, interface = Ethernet0 :
00 01 08 00 06 04 00 01 00 e0 fc 2c 9f e6 c0 a8 21 01 00 00 (源IP)
00 00 00 00 c0 a8 1f 02 (目的IP)
ARP: drop not same net address Arp Request, interface = Ethernet0 :
00 01 08 00 06 04 00 01 00 e0 fc 2c 9f e6 c0 a8 21 01 00 00
00 00 00 00 c0 a8 1f 02
可见,我司的路由器把和自己不同网段发来的ARP请求给丢掉了。
在这里要非常感谢我们的朱皓同学的建议和指导,他帮我纠正了文中大量的错误,亲自设计并完成了这个试验,给了我很大的帮助。
下午看到了杜祥宇老师的提出了一个改良方案。是在AB两边服务器上都配置一个静态主机路由指向各自所在的网段中未使用的IP地址X,再配置一个静态ARP表项把这个IP地址再绑定到另一台服务器的MAC。这样当服务器A发现要发向B的报文的时候,会首先想到向X发送报文(它被骗了),于是查找ARP表,发现那个被绑定的MAC地址(其实也就是B的MAC,可怜的主机又被骗了),于是就在DMAC中填入B的MAC地址,然后发送报文。这样一来,B的链路层收到一条打着自己MAC地址的报文,于是连忙向上提交,IP层一检查,目的IP也是自己,于是又提交给它的上层,于是B就收到了A发来的报文,然后回复,道理也和发过来一样。这样,两台服务器之间终于可以无阻碍地互相通信了。
终于这个问题得到了圆满解决的答案。
正好在三天前,也就是上周六的晚上,我们几个新来的同事也在讨论LAN的问题,索性就搬了台交换机来做试验,刚好也做了一个差不多的试验。
试验是这样的,在一个二层交换机(S1)上连接了两台主机(h1和h2),这两台主机都是XP系统,分别设置了两个不同网段上的IP(192.168.1.1/24,10.1.1.1/8)。
1。都不设置网关,互相ping,结果是不通;
2。h1(192.168.1.1/24)设置网关为自己,h2不设,互相ping,还是不通
3。双方都设置各自的网关为自己,互相ping,能够接到回应
4。设置对方为自己的网关,互相ping,能够收到回应
照老大的话说Gateway就是下一跳地址,如果主机在自己的路由表里查不到目的IP的路由,不知道该把报文发给谁,它就把报文发向默认Gateway,让默认Gateway来转发,从而避免主机不知道该把报文向哪里发的情况。(如果目的地址在主机自己的路由表里找不到,并且也没有默认Gateway的话,主机就认为目的地址不可达)
所以如果我们都不设网关,那么自己的报文(发到其他网段的报文)找不到下一跳,连发都发不出去;如果只有一边设置了网关的话,即使报文能够顺利的抵达目的,对方也无法回复,因为对方不知道你的路由,也没有默认Gateway;我猜想,双方都设置了网关的话,可能报文会走一个三层转发的过程(猜的,有条件抓个包看看);至于那个设置对方为自己网关的想法虽然只是突发奇想,但是却居然能通,这个多少让我们觉得奇怪,从抓包的结果看,WinXP系统并不检查自己的网关和地址是否在同一个网段,在查到默认网关以后,直接发送ARP查询默认网关的MAC地址,而收到ARP的一方,同样不检查这个ARP的请求者是否和自己在同一个网段,便直接回应一个ARP答复,这样两边就都获得了对方的MAC地址,所以竟然能够互相通信。
加一句老大的话:“gateway设置成自己,实际上就是和我说的配置的静态路由指向接口,而不明确指向下一跳地址效果一样。”
对了,我们这个试验只是在XP下成功了,但是在其他的系统中照着上面的配置,是不是也能够相互通信就不得而知了。如果h2的ARP模块实现要用自己的mask为标准,来检查h1的IP地址和本接口的IP地址是否在同一网段上的话,单单设一个gateway恐怕就不够了。
首先,在这里我们要先明白IP转发的过程,才能了解为什么会讨论出这个结果。
转发过程如下:
1.主机在发送之前,先检查自己的路由表,看目的IP是否和自己是同一网段
2.如果gateway是他自己(PC将和自己同网段的gateway设为自己本身),他认为这样的转发属于二层转发,于是把剩下的事情交给链路层去做,然后链路层查缓存里的ARP表里有没有,有就直接送2层转发
3.如果ARP表里没有,那么就进入ARP过程,请求目的IP的MAC地址
4.如果目的IP的Gateway不是他自己,则认为和自己不是同一网段,就进行3层查找,也就是说找路由表,找到最长匹配的项。(一般要是找不到的话,默认网关就是最匹配的)。如果是PC会直接交给链路层查找Gateway的MAC地址转发,如果没有,则发送ARP请求网关MAC地址,然后发送,到此报文发送完毕。
5.如果是在路由器上,还可能进行递归查询,如果下一跳地址非直连网段,进行递归查询,找下一跳的路由。
6.反复递归查询后,如果没找到下一跳为直连网段的路由,那么不可达。
7.如果找到匹配的路由,且下一跳为自己的直连网段,那么将进入ARP过程,请求下一跳的MAC地址,按照下一跳MAC地址传送数据。
8.到达下一跳后反复上面的过程。
9.如果所找到的路由的下一跳为本地环回口,也就是自己的IP,那么后面的操作就可以看作和step 2的过程一样了
我想最后一种方法就是利用了红色的那部分文字所说的过程,A上层想发送一个报文给B,于是A的IP层就在自己的路由表中查找去往B的下一跳,很快它发现X可以帮它转发报文,于是兴高采烈把B的IP写到目的IP地址中,然后告诉它自己的链路层把这个报文发到X去,于是A的链路层就开始搜索自己的ARP表,发现我们为它设置的静态ARP表项X的MAC地址,于是就在报文的目的MAC地址中填入我们为它设置的MAC地址,然后交给物理层发送。这样我们成功的让A发出了一份目的MAC和目的IP地址都是B的MAC和IP地址的报文。这样的报文到了A的物理层自然而然的被一层层的向上提交,于是达到了我们一开始希望它们互相通信的目的了。
当然,这个问题最后让我们了解了IP报文转发过程中的一些细节问题,像我这样刚开始接触这个行业的人而言,对于很多东西的理解都还只是想当然的以为应该这样或应该那样,在学习的过程中也只是了解个大概的理论、概念和过程,很少有心思去挖细节。通过这次讨论,了解了很多以前没有注意到的细节过程,对于前段时间的学习疏漏的地方做了及时的补充,顺便将其记录下来,为以后大家的讨论提供方便。