通过前文(Linux环境下openVPN的配置)所述,我们已经可以将异地他乡(本地局域网外,准确说是同一物理网段外)的电脑和本机联接起来,成为一个逻辑网段内(VPN网络,Virtual Private Network)。这样以来,我们就可以像在同一个局域网内一样使用他们了。本文中要讲述的,是在此基础上,如何让我们VPN内的主机通过VPN网络中的网关来访问我们VPN网络的外部互联网。看下图:

我们先看图说话。在前面的文章中,我们已经通过openVPN,将位于局域网中的客户端丁、客户端庚与位于互联网上的VPN服务器组成了一个局域网。网段是10.8.0.0/24。从上面这个图上我们可以看出,两个客户端都可以通过路由器链接到互联网,从而和VPN服务器链接,才有了openVPN施展的空间。那么我们为什么还要在此基础上,让客户端通过VPN服务器链接上互联网呢?换句话说,本文有哪些应用场景呢?

其实应用可大了。虽然客户端们可以链接到互联网上,并能和VPN服务器通信。但是如果我在路由器上做一个防火墙规则,禁止客户端们链接VPN服务器以外的服务器;或者除了端口80和8080外,禁止客户端链接互联网上任何主机的其他端口。简单的说,客户端们虽然能够链接上互联网,但是他们的链接是(部分)受限的链接

说到这里,我想很多人立刻就能想到一些场景了。比如在公司,办公室里所有的电脑都在一个子网内,并且通过公司的路由交换设备,统一联接到互联网。为了防止员工上班时间聊天上网打游戏,公司在路由器上设置防火墙规则,将80端口以外的链接都禁止掉。这样以来员工们都能上WEB浏览网页、查询资料。但是干不了别的事儿。

不过某君比较幸运,他在互联网上有一台自己能够操控的服务器——VPN服务器。由于他可以通过80端口正常联接到VPN服务器,所以他可以将VPN服务器的VPN服务打开,并且监听80端口。这样一来,他就可以将公司里自己的电脑(图中的客户端丁、客户端庚)和VPN服务器通过openVPN链接起来,这样以来,客户端和VPN服务器之间的所有通信(包括非80端口的通信),属于VPN子网的内部交流。这部分交流,由openvpn进行处理之后,打包成并发送到VPN服务器的80端口进行处理。

说到了这里,我们就已经做到了第一步,那就是已经小范围(VPN网络内)实现了突破路由器的端口封锁策略了。上面说到VPN,凡是VPN子网的内部交流,都会被openvpn打包后发送到VPN服务器的80端口中。这里是怎么实现的呢?稍微有点网络知识的朋友们,应该想到了——路由。

原来,openvpn客户端启动的时候,会增加新的路由规则,使得发送到VPN子网的数据,不会直接通过路由器发出去,而是由openvpn处理打包成对openvpn服务器器80端口的请求,然后再通过路由器发送出去。这里就是我们怎么突破路由的端口封锁的原理了——

  • 将各种端口的请求进行二次打包,打包成对VPN服务器的80端口请求

  • 然后正常的通过路由器转发打包后的请求,由于是发送到VPN服务器的80端口数据包,因此不会被拦截封锁。

  • VPN服务器在接到包之后,再解包得到真实的请求。

反过来也是一样:

  • VPN服务器将各种端口的通信数据打包,通过80端口提供服务;

  • 路由器通过VPN服务器的80端口提取到数据,然后根据路由器自己的路由规则,转发给客户端;

  • 客户端接受到通信数据,通过openvpn解包,得到真实的通信数据。

由前面的示意图,我们可以看出,VPN服务器是可以自由访问因特网上的资源的,比如服务器甲、服务器乙上面的资源。客户端们只能受限制的访问。但是由于有了openVPN,客户端们可以无限制的访问VPN服务器上的资源。

因此,我们只需要将客户端们对因特网上的资源的访问,通过VPN服务器进行中转,就能够达到客户端访问互联网上所有的资源的目的了。怎么实现呢?答案很简单——还是路由。

<li>为什么我们访问VPN服务器上的任意资源可以成功?

因为我们访问VPN服务器上任意资源的时候,路由是VPN服务器。所以内核在接到访问请求的时候,会把数据包给openVPN打包,然后在发出去。

<li>为什么我们访问其他互联网资源不能成功?

因为我们访问其他资源的时候,路由默认是我们的路由器,内核接到访问请求的时候,直接发出去了。

所以,我们之需要在访问其他互联网资源的时候,也将VPN服务器作为默认的路由,内核受到访问的数据后就会交给openVPN打包,再转发出去了。即——在客户端这边,只需要修改默认的路由为VPN服务器即可将所有的请求通过VPN服务器来转发。知道了这一点,方法就很简单了:

#这里表示发送到默认网段(在路由表中没有明确指定的所有网段)的所有请求,网关地址是10.8.0.1

这里先删除原来的默认路由设置,然后添加我们新的路由设置。添加之后,路由记录里就应该有下面的记录了:



Destination Gateway Genmask

default 10.8.0.1 0.0.0.0

这里有一点需要注意,由于10.8.0.1只是openVPN虚拟出来的一个路由。所有的数据包,在经过openvpn打包后,最后物理上还是通过路由器192.168.1.1来转发的,只不过这个时候数据包的目的地址已经变成了VPN服务器了。所以,我们还要确保发送到VPN服务器的数据包的路由,仍然是路由器192.168.1.1,这样我们打包后的数据包才能真正的发出去。



route add -net 222.210.17.17/32 gw 192.168.1.1

#这里的222.210.17.17/32表示发送到222.210.17.17、掩码为255.255.255.255网断的请求,网关地址为192.168.1.1。

客户端的设置就搞定了,在VPN服务器上我们也要设置一下才行。因为我们的数据包虽然转到的VPN服务器,经过openVPN解包后,也得到了真实的地址,根据VPN服务器上的路由表,最后也将这个包发到因特网上的这个服务器上了。但是数据包的来源地址是10.8.0.5这样的VPN子网的地址,服务器接到这个包后,会将响应的结果直接发给因特网上的10.8.0.5,我们知道这个地址在因特网上是不存在的,只能在我们这种子网上才存在。所以就会造成我们的数据包能发出去,但是对方发不回来。

怎么处理这个问题呢?当然是用iptables来在发出去的时候自动修改来源地址为VPN服务器了。这样服务器会将处理后的数据传给VPN服务器,VPN服务器再通过查询刚才发出去的包记录,将收到的包的目的地址改为10.8.0.5这样的VPN子网地址,然后转发到我们的机子上来。方法如下:



iptables -A INPUT -i tun0 -j ACCEPT

sysctr net.ipv4.ip_forward=1

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



第一行的作用,是将VPN子网发来的请求全部允许通过。

第二行的作用,是打开内核的转发功能,这样才可以将从VPN子网得到的请求通过因特网转发出去。

第三行的作用,是将通过因特网发送出去的数据包中,来源地址为10.8.0.*的数据包,来源地址修改为VPN的互联网公网地址。并且在收到该包的相应的时候,将目的地址又VPN服务器的公网地址修改回10.8.0.*这样的地址。

不过最后还有一个问题,如果我只是将客户端的某些请求通过VPN服务器进行中继,而不是所有请求,该怎么处理呢?路由这种方式显然是针对IP过滤的,如何针对端口过滤呢?思考中……