OpenVPN虚拟网络拓扑剖析

OpenVPN虚拟网络拓扑剖析

By jfo,

 

转载请注明出处http://blog.pickbox.cc/2008/07/07/openvpn%E8%99%9A%E6%8B%9F%E7%BD%91%E7%BB%9C%E6%8B%93%E6%89%91%E5%89%96%E6%9E%90/

 

OpenVPN-

server/client配置模型

sample-config-files:http://openvpn.net/index.php/documentation/howto.html#examples

Ø 点对点VPN tunnel网络拓扑

server .0 255.255.255.0

一旦client连接上,tun设备相当于虚拟出一个网关

服务器端(Linux)的路由如下:

所有VPN .0/24子网段都经由10.10.10.2处理,网关10.10.10.2可以判断目标地址,查找内部记录的信息,将数据包发送给正确的客户端。

客户端(Windows)的路由如下:

所有VPN .0/24子网段都经由10.10.10.5处理,网关10.10.10.5可以将数据包通过隧道发送出去。

当一个用户程序,如FTP,向.1发出连接请求时,这个数据包进入到内核,查找路由表,发现需要经过10.10.10.5这个网关从10.10.10.6(即和虚拟网关相连的网络出口,类似普通网卡接口)发送出去,而网关10.10.10.5其实是OpenVPN底层驱动虚拟出来的,于是数据包从底层被发送到OpenVPN用户程序,OpenVPN可以进行VPN虚拟IP封装、记录真实IP等工作。然后OpenVPN修改数据包的src IP和dest IP为底层网络的真实IP,发送到另一端的OpenVPN服务端或客户端。

另一端接收到数据包后,由内核交给上层OpenVPN应用程序,OpenVPN可以对这个数据包作任何操作了(数据包格式OpenVPN自己是知道的),比如从中提取出VPN虚拟IP,甚至发送方的真实IP,这些信息和后面将提到的multiple machines on the server side以及multiple machines on the client side都有关系。

不论是发送还是接收,虚拟网关(.2和10.10.10.5)都记录下VPN虚拟IP和真实IP:PORT的对应关系。

整个过程用户看上去就像是经过了一个隧道,其中的细节全部被隐蔽了。但值得强调的是,最终数据仍然是以真实IP在网络上跑的,这也符合一般设计逻辑。

Ø multiple machines on the server side

ref for detail:

在sample-config-files中有如下一段配置:

描述的情形如下图所示(稍作修改,192.168..网段替换成了.*网段):

push “route .0 255.255.255.0” 的作用是将route命令push到连接进来的client,设置client的路由,实际上也可以在连接后手工设置。

客户端将所有.*的请求全部经过虚拟网关.5(即VPN隧道)发送到VPN服务器。

服务器端只要允许了IPTUN/TAP forwarding,就可以将数据包转发给正确的机器。

从这一点可以看出,OpenVPN所做的工作只不过是建立通讯隧道、封装一些新的信息到数据包,以及还原数据包和提取真实目标地址信息。也就是说服务器端默认就会转发数据包的,而不需要OpenVPN另外单独做路由判断或是发送目标地址过滤等操作,这些都是底层原有的机制(如iptables,routing tables)完成的。这也说明了为什么即使在服务器的配置文件中不添加push “route .0 255.255.255.0”这一行,只要client端手工添加了这一路由项,都可以成功发送至服务器端内网的任何一台机器。

文档中特别强调了一句:“Remember that these private subnets will also need to know to route the OpenVPN client address pool (.0/255.255.255.0) back to the OpenVPN server.”

这句话是说,服务器背后的内网在回复VPN客户端时,要知道将.0/24这个OpenVPN虚拟IP的路由回OpenVPN server上,这在OpenVPN服务器与网关不是同一台机器时尤为重要。这句话暴露出这样一个信息:数据包是以OpenVPN虚拟IP在server私网跑的!

为了进一步验证这一发现,我们先在客户端用FTP连接服务器内网的一台FTP服务器(.241),然后在服务器端运行如下命令(conntract记录了网络当前数据包的各种信息),从结果可以看到,src=10.10.10.6,确实验证了这一点。

这说明OpenVPN服务端收到数据包后,会从中抽取出VPN虚拟IP(前面我们说过,OpenVPN会封装进一些附加信息,虚拟IP就是其中之一),然后用它替换数据包的src address,最后转发出去。

再次回到文档中的那句话,当OpenVPN服务器与网关不是同一台机器,我的实验环境就是这样,而你又不是网络管理员,无法更改网关的设置时,那么只能说抱歉了,通过设置push “route .0 255.255.255.0”的方法,你仍然不能访问到服务器端内网,你的FTP客户端将不断显示“延迟30秒尝试重新连接”!因为回应数据包无法从内网发送出去。

如果你有足够的怀疑精神,也许你会问,如果是这样,网关肯定不会将你的OpenVPN连接请求转发到内网自己的OpenVPN服务器(通常情况都会这样),那么从一开始网关就会拒绝我的OpenVPN连接,更不会有后面的通过“sudo cat /proc/net/nf_conntrack”验证数据包了!你说的一点也没错,然而事实是我确实成功的验证了src=.6,这说明OpenVPN连接确实成功建立,那么网关被我设置过?可我又没有配置网关的特权,也不要怀疑我和网管是好朋友,那么只能说明我通过某种非常规途径建立了OpenVPN连接!推断完全正确,事实正是如此。详情请参考http://blog.chinaunix.net/u/10449/showart.php?id=688463,介绍的是如何穿越NAT对外提供服务。

之所以提这一小插曲,是因为当我们处于迷惑不解的状态时,例如调试一个内核的bug,搞到晕头转向,也找不出丝毫的蛛丝马迹,这时人们最容易草木皆兵,到处怀疑可能出错的地方,就算我们平时会拍着胸脯说绝对不会有问题的地方,也难逃被怀疑的厄运。这时最重要的是正确的推断,根据眼前可以确认的事实,一步一步追根朔源,找到矛盾的源头,而不是怀疑自己眼前看到的事实,花费大量精力在很可能正确的地方挑错。相信你曾有过这样的经历:明明在街上看到某位朋友,可是回头问时却被否认,于是你开始怀疑自己确实是看错了人。

言归正传,总结一下,当multiple machines on the server side时,客户端从外网通过VPN隧道访问内网机器,在内网使用的是VPN虚拟IP!并且push “route .0 255.255.255.0”不会对服务器端有任何特殊设置,它仅仅指导客户端添加一项路由。

另外可以试着将VPN虚拟地址指定成.0/24网段,这时不向网关添加任何路由信息,会不会成功?

 

Ø multiple machines on the client side

ref for detail:

描述的情形如下图所示(稍作修改,192.168.40.网段替换成了192.168.1.网段):

route 192.168.1.0 255.255.255.0的作用是在server端添加路由项。实际上也可以手工添加。

server在接收到目标地址为192.168.1.0/24的数据包时,根据路由项将数据包从内核传递给OpenVPN应用程序,OpenVPN再根据iroute 192.168.1.0 255.255.255.0查找出192.168.1.0对应着哪个客户端子网,选择正确的VPN隧道,将数据包从OpenVPN server发送出去。iroute不能手工添加的,它被OpenVPN内部使用。How-to文档中有这么一段描述:“route controls the routing from the kernel to the OpenVPN server (via the TUN interface) while iroute controls the routing from the OpenVPN server to the remote clients. Both are necessary.”

最后一步,也是经常被忘记的一步,是向server端的网关添加一项路由,将所有目标地址为192.168.1.0/24的数据包转发到OpenVPN服务器。(The last step, and one that is often forgotten, is to add a route to the server’s LAN gateway which directs 192.168.4.0/24 to the OpenVPN server box)

这一步又向我们暗示了一个信息:client端的任何一台机器访问server端内网机器时,在server端内网显示的是客户端LAN的真实IP!

client-to-client

push “route 192.168.1.0 255.255.255.0”

另一台client2连接server后,它的route table将显示192.168.1.0的路由项

Ø 其他说明

EXAMPLE: Suppose you want to give

Thelonious a fixed VPN IP address of .1.

First uncomment out these lines:

;client-config-dir ccd

;route .0 255.255.255.252

Then add this line to ccd/Thelonious:

ifconfig-push .1 10.9.0.2

将ifconfig push到客户端配置,由于server .0 255.255.255.0,默认只会对10.8.0.0/24路由,因此需要添加route 10.9.0.0 255.255.255.252,对10.9.0.0/30路由

push “redirect-gateway def1”

push “dhcp-option DNS .1”

push “dhcp-option WINS .1”

将客户端默认网关配置成服务器端。并设置DNS server和WINS server为.1

OpenVPN server端必须配置如下:

iptables -t nat -A POSTROUTING -s .0/24 -o eth0 -j MASQUERADE

Ø 最终的全景图

OpenVPN仅仅建立隧道,并封装一些必要的信息,例如VPN虚拟地址和客户真实地址,其他的所有网络扩展,例如访问server端内网、访问client端内网,都是利用基本路由,以及iptables规则实现的。

也就是说一旦OpenVPN的基本配置完成后(唯一例外的是iroute这一配置项),完全可以自行手工设置路由以及iptables规则,来实现对网络的扩充,了解这一点对配置安全网络尤为重要,不要指望只要在server端不写类似”route .0 255.255.255.0”的语句就可以阻止客户端访问服务器内网,你必须从iptables规则链中确认客户端访问会被过滤掉。了解这一点也会帮助你构建基本网络,在路由器和交换机的重重封锁下,可以通过建立一条VPN隧道打通两个子网之间的网络通路,然后考虑如何通过添加路由和设置iptables规则,实现扩充VPN隧道功能的目标。


 

#end