OpenVPN内部实现了一个路由器的功能,其源代码的multi_get_instance_by_virtual_addr函数执行路由查找的工作,这种路由是OpenVPN的内部路由,也就是说这种路由是OpenVPN配置并查找的,和外部的系统路由是完全独立的。
OpenVPN内部路由和系统的路由之间的区别在于,系统路由完全照着最长前缀匹配原则,找到路由之后,将数据包从对应的网卡接口转发出去。而OpenVPN内部的路由虽然最终也是决定是否转发并且往哪里转发数据包,然而这个“是否转发”以及“往哪里转发”是和系统路由大大不同的,OpenVPN是否转发数据包依照的其内部的一张路由表而和系统的路由表没有关系,往哪里转发呢?其实是往两个地方转发,根据查找内部路由得到的结果,如果目的地址不是其它OpenVPN客户端的或者这些OpenVPN客户端后面的网络主机的,那么就往自己的虚拟网卡中转发,如果目的地址是其它OpenVPN客户端的或者其后面网络的,那么在开启C2C的情况下,直接转发到对应OpenVPN的socket,转发前用对应的socket实例的安全参数进行OpenVPN协议封装,C2C是不是很像linux中的ip_forward内核参数呢?
注意,前面的阐述中,我一直都在说目的地址,而没有说目的IP地址,这是因为OpenVPN的内部路由不仅仅是IP路由,在tap模式下,它的内部路由实际上是链路层的路由,这时OpenVPN服务器不是一台路由器,而是一台交换机,还是一台可以“动态学习MAC地址”的交换机,因此tap模式下,OpenVPN内部路由其实就是交换机的链路层路由,其路由表其实就类似于交换机的MAC地址表。
OpenVPN内部路由的职责有:
1. 抉择是否转发到来的已经解除了OpenVPN封装的载荷数据包。也就是载荷包的发起者是否在OpenVPN的策略范围内;
2. 处理不同OpenVPN客户端之间的通信以及不同客户端后面所挂接的网段主机之间的通信。也就是说在上述这些主机之间路由数据包,注意这里所谓的路由并不是协议栈中的IP路由,而是OpenVPN内部的路由。
OpenVPN可以通过内部路由扩展成一个巨大的网络,该网络直接穿越不安全的网络区域,比如互联广域网或者城域网,是这个扩展而成的巨大网络真正的成了虚拟的和专用的,这就是OpenVPN对于网络拓扑支持最强大的地方,OpenVPN另外的强大之处前面的文章都快说烂了,比如和SSL结合,和PKI结合等等,在和主机网络协议栈结合处,OpenVPN使用了虚拟网卡,这也快说烂了,因此本系列文章着重谈OpenVPN的强大路由功能。如果能彻底理解这个,那么相信你已经理解了其它,进而阅读源代码和修改定制源代码已经不是什么困难事了,因此本系列文章不再冗余的分析源码。
那么,被OpenVPN扩展而成的网络到底是什么样子呢?这要看你使用tap模式还是tun模式了:
tap模式下,VPN节点(多个客户端和一个服务器端)组成了一个以太网,而VPN服务器就相当于一台以太网交换机。由于以太网是IP协议栈下层的封装,tap模式下的所有VPN节点以及节点后被bridge的节点组成了一个大的以太网而不是IP网络,OpenVPN内部路由是作用于MAC地址的,对于任意来源IP,OpenVPN内部路由都是直通的,写入虚拟网卡后,由系统路由判决。因此tap模式下,如果需要各个VPN节点后面的网络之间达到IP互通的效果,那就必须要么做NAT映射,将VPN节点后面的网络NAT到VPN节点,要么辅助以系统的IP路由,而这些配置很复杂,很难维护。见下图:
tun模式下,VPN节点(多个客户端和一个服务器端)以及其它允许接入的网络(通过iroute配置)组成了一个IP网络,而VPN服务器就相当于一台IP路由器。tun模式下的所有VPN节点以及节点后被iroute内部路由以及系统路由指向的节点组成了一个大的IP网。此模式下,内部路由和系统路由共同起作用,OpenVPN的事件机制可以将这二者无缝结合。见下图:
OpenVPN事实上通过定义良好的衔接口和既有的优秀框架结合,这些衔接口分别是SSL协议/PKI,虚拟网卡/主机协议栈,内部路由/事件机制/系统IP路由。OpenVPN既做到了机制的完整,和外部框架的结合,又给了用户灵活的配置,因此,OpenVPN很棒。