ICMP重定向消息在OpenVPN多子网互通中的应用

晨曦之光 发布于 2012/04/10 14:56
阅读 249
收藏 1
RFC792描述了ICMP协议,其中关于重定向消息的部分描述如下:
The gateway sends a redirect message to a host in the following situation. A gateway, G1, receives an internet datagram from a host on a network to which the gateway is attached. The gateway, G1, checks its routing table and obtains the address of the next gateway, G2, on the route to the datagram's internet destination network, X. If G2 and the host identified by the internet source address of the datagram are on the same network, a redirect message is sent to the host. The redirect message advises the host to send its traffic for network X directly to gateway G2 as this is a shorter path to the destination. The gateway forwards the original datagram's data to its internet destination.
For datagrams with the IP source route options and the gateway address in the destination address field, a redirect message is not sent even if there is a better route to the ultimate destination than the next address in the source route.

重定向消息一般用于通知“这不是一条好的路由”。对于共享介质的网络,特别容易出现这种消息。如下图所示:


千万不要认为ICMP路由重定向消息是什么错误消息或者是一种“额外”的消息,它可是生成路由转发表要素的三种来源之一哦,另外两种是静态路由和路由协议生成的动态路由。如果你不相信这一点,在Linux上可以在收到路由重定向消息后运行route –C –n查看路由缓存,实际上重定向的路由已经开始起作用了(有个前提是你已经允许接收路由重定向消息,这个由sysctl来控制)。
       前面我们已经理解了ICMP路由重定向的理论,那么怎么合理的利用它呢?如果你想制造一些应用场合,那是很容易的,然而ICMP重定向在这些场合生成路由并不是最优的做法,我们需要找一种场合,在该场合中,使用ICMP重定向消息生成路由即使不是最优的方式,起码也是一种很不错的方式。到底是什么场合呢?那就是OpenVPN在tap模式下实现客户端子网和服务器端子网所有N个子网间的互通。拓扑图如下:

我们知道,tap模式下所有的客户端节点和一个服务器节点构成了一个虚拟的以太网,不管虚拟与否,起码它是一个以太网,遵循所有的标准以太网协议,比如以太网arp协议以及以太网广播等,在开启client-to-client的情况下,客户端M要想访问客户端N后面的子网,那么需要将访问该子网的网关设置成客户端N的虚拟IP地址,这是十分显然的,手工配置一下,瞬间可以证实。然而这是有问题的,对于一个稳定的虚拟专用网,所有子网的IP段基本是固定的,然而由于各种原因,各个节点被分配的虚拟IP地址可能会发生变化,一旦它们发生了变化,就要想办法通知所有其它节点更新其到该变化了虚拟IP节点后面子网的路由,这是一件很麻烦的事情,搞不好就会弄错,当然你可以为某一个固定节点分配固定的IP地址,可是我还是不喜欢这种方式,因为这需要人工来维护这份地址表,也不简单。
       由于我们的需求仅仅是客户端子网之间互联互通,那么完全可以隐藏掉关于虚拟IP地址的配置,使其不体现在配置界面上更好。所有的关于虚拟专用网的路由都采取默默推送的方式进行,完全隐藏在内部。因此,很直接的方式就是ICMP路由重定向消息的利用,使用这种消息来自动生成路由,这样只需要OpenVPN服务器端知道各个OpenVPN客户端后面的子网并设置路由指向分配给该客户端的虚拟IP地址即可,而这十分容易,只需要简单的写一个client-connect和client-disconnect脚本即可。然后所有客户端将访问其它客户端子网的路由指向OpenVPN服务器的虚拟IP地址。这样当有客户端发起这样的访问时,OpenVPN服务器会发送ICMP路由重定向消息给OpenVPN客户端,这样OpenVPN客户端便自动生效了这个重定向路由,十分不错。
       这里有个需要注意的地方,那就是OpenVPN客户端需要定期执行ip route flush cache来刷新路由缓存,这样做为了发现其它客户端由于重连等原因更新了虚拟IP地址,从而使OpenVPN服务器端推送新的ICMP路由重定向消息,如果不刷新缓存,那么万一有长数据在传输,比如没有确认的ping或者udp的syslog,ntp等,就会永远不可达,刷新了缓存之后,这些数据发往OpenVPN服务器,此时该服务器就会推送下来新的ICMP重定向路由。

杂项:链路层复用带来的问题

编程界有IOCCC,我觉得网络界也应该有个类似的,其宗旨在于:
1.用讽刺的手段显示网络规划的重要性
2.用反常的配置让网管精神崩溃
3.显示网络协议栈不为人知的细节
4.为无意犯错的高手网管提供避难所
5.为突破常规方法带来的限制提供解决方案
《西厢计划》其实可以作为网络界一个典型的IOCCC作品,网络协议栈的设计者和C语言的设计是同一类人,他们都有相同的梦想,都是一类家伙,那个时代是疯狂的时代,是黑客的时代,然而我们现在,网络和编程变成了两回事!C语言可以写出那么混乱的代码,那是因为设计C的家伙本身就是个黑客,他关注的更多的是C语言本身,是如何让和他一样的黑客可以更好的控制计算机,而不是在上面跑什么应用,而网络协议栈的设计者也是同一类人,他关心的是如何使黑客们可以更方便的通信,而不是这种通信能给谁带来什么效益。因此网络协议自设计一开始就是开放的,是不设防的。所以才为如今一些疯狂的人留下了一个粪靶子。
下面是一个关于ICMP路由重定向的配置
主机1:两个网卡,同时接到交换机A,然而配置不同网段的IP地址,启动路由,默认网关指向主机3
主机2:一块网卡,将访问网络A的路由指向主机1的网卡1,该主机的网卡和主机1的网卡1处于同一IP网段
主机3:两块网卡,网卡1连接在交换机A,网卡2直连网络A
在主机2上访问网络A,数据包该怎么走呢?这是一个问题。
1.首先主机1会发送arp请求,请求主机1网卡1的mac地址;
2.主机1收到arp请求后,默认情况下,网卡1和网卡2均会回复这个请求,因为它们复用了链路层
3.假设主机2接受了主机1网卡1的mac地址那么接下来主机1会发送ICMP重定向消息
4.而如果主机2接受了主机1网卡2的mac地址,那么由于网卡2的IP地址是另一个网段的,接下来将不会发送ICMP重定向消息,数据包将由主机1的网卡2接收,然后通过其网卡1转发出去给主机3
因此上述的配置导致的数据包路由是不确定的,那么它受什么影响呢?实际上有很多因素,在物理层,它受到交换机拓扑的影响,到底主机1的网卡2和网卡2的arp回应哪个会生效,这就要看网线是怎么连接的,看看谁“离主机2更近”,构造交换机环路可以对其造成影响,另外还受到内核配置的影响,在linux中,可以通过配置网卡的arp_ignore来影响arp回应的发送,另外还受到是否发送和接受ICMP路由重定向消息来影响数据包的路由,在linux中可以配置网卡的send/accept_redirect。



原文链接:http://blog.csdn.net/dog250/article/details/7099474
加载中
返回顶部
顶部