暑假以来一直在做这个东西,希望找到一套合适的解决方案。这几天把找到的解决方案挨个实现了一遍(有的是别人实现的),写下本文供大家参考。
  题目的“IPv6 VPN”是指“VPN over IPv6”,也就是跑在IPv6网络上的VPN,作为IPv4 over IPv6的一种实现形式,用于连接被IPv6网络分隔的IPv4孤岛,同时稍作修改也可以在VPN内实现纯IPv6网络或双栈网络。技术上难度并不大,主要是想法难得——我是在参与讨论yegle组织合租服务器时经winsty提醒想到的。最初的想法是客户端通过IPv6连接服务器,然后将服务器当作网关上网用。这就要求服务器运行双栈协议,可以经IPv6连接到客户端,同时又可以无限制的访问IPv4网络。这个想法并不隐含VPN,比如Cisco路由器Solaris都自带IPv4 over IPv6隧道支持。最先成型的解决方案是IPv6直通车,基本原理是自己写了个小工具,监听IPv4指定端口,把数据通过IPv6转发出去,用OpenVPN建立IPv4 VPN。效率并不敢恭维,但稳定性无疑是最好的,成本也最低(对一个人而言)。之后就再也没有成型的解决方案了,需要我们DIY。VPN无疑是最自然的起点,目标就是让我在学校可以上网,服务器端用Linux,客户端既有Windows XP,又有Linux。
  符合条件的服务器我找了一下,主要提供商有HEFDCServersKimsufi等。需要说明的是从中国到美国西海岸有200ms左右的延迟,tcp三次握手,来回就是600ms,浏览网页还是能感受到的,到英国的话,单程要300ms+。中国似乎只有DNS3G一家提供IPv6网络。
  HE提供的机器是

Ok, we've just added a new item to our price list of a "Green" Power Efficient Dedicated Server (Core 2 Duo processor with 2 GB of RAM and 500 GB HD) including an unlimited 100 Mbps (no traffic charges) port for $69/month $260 one time setup that could be used for you to run a tunnel over IPv6. Let me know if this interests you and then I'll have a sales person quote you. The IPv6 tunneling aspect of your service is a custom configuration which we will include for free.

  FDCServers的最低价是$99/mon,Kimsufi可以开到£19.99/mon(是Ovh下属的一家公司,但只对英国人服务,在英国有亲戚朋友的可以考虑)。DNS3G从5K到数万不等(/year)。
  后文假设已经找到了合适的服务器(没找到的可以发信给我,我给你找地方),并且在服务器上运行Linux系统(最好是debian),且基本熟悉Linux的各种管理工具。

  jameszhang的基于IPv6的IPv4透明隧道建设尝试提出了一个非VPN的方案。这个方案的原理是在两个Linux机器上建立tap设备转发数据包,效率比起OpenVPN等使用tun设备的VPN要差一些,但省去加密,还是可以折平的。但一来出于“安全”考虑,我们必须要加密,二来这个方案完全不支持windows,故被我弃用。

  接下来还是考虑基于VPN的方案。基于L2TP的VPN最近很热门,在无人区@寒水远山有详细叙述,已经被实现且正在为他们服务。但Windows XP却享受不到。

  OpenVPN在数年之前就有过讨论是否添加对IPv6的支持,但终没有被加入到特性中,只有juanjo开发了一个udp6补丁。这个系列的补丁我尝试过(with Yangzhe1990),确实能在debian上跑起来,但却明确不支持windows,中间juanjo似乎与社区失去了联系。但这是我当时能找到的最好的解决方案,还是断断续续的跑了近1个月。现在,好消息是——juanjo已经回来了,受聘于Google并且将此作为他的“20% project”。在这里已经可以看到代码和编译好的binary。目前已经支持windows平台,debian sid的openvpn已经整合了这个补丁,ubuntu的deb包由Bernhard提供。
  配置OpenVPN服务器的过程可参考这里。不同的是现在easy-rsa/下又分了1.0和2.0两套,我们需要的是2.0的,同时不需要ta.key。基本步骤大概如下所示:

1. 将examples复制到oepnvpn的配置文件目录,方便使用。
# cp -r /usr/share/doc/openvpn/examples /etc/openvpn
2. 将vars里的KEY_COUNTRY, KEY_PROVINCE, KEY_CITY, KEY_ORG及KEY_EMAIL参数改成自己的值。
# cd /etc/openvpn/examples/easy-rsa/2.0/
# vim ./vars

3.接下来设定服务器端:将vars的参数load到环境中,并将旧的key或设定清除,建立root certificate。
# source ./vars
# ./clean-all
# ./build-ca

完成后会在keys/下生成ca.crt和ca.key。
4. 建立服务器的证书。
# ./build-key-server server
server是指服务器的名字,完成后生成server.crt、server.csr和server.key。
5. 建立客户端的证书。
# ./build-key client
因为Windows客户端默认不支持密码,故建立的是无密码key。client指客户端的名字,完成后生成client.crt、client.csr和client.key。
6. 建立 Diffie Hellman parameters。
# ./build-dh
会生成dh{n}.pem。
今后若要添加客户端,则需重复source ./vars及5、6两步。
服务器端的/etc/openvpn目录下需要ca.crt/key、server.crt/key和dh{n}.pem(这几个文件直接放在/etc/openvpn下则后面的配置文件中不需要写路径),ca.crt、client.crt/key需要分发给客户端。

  服务器端还需要server.conf,可以在examples/sample-config-files/server.conf基础上修改,将proto改用udp6或tcp6(udp6好一点);ca、cert、key、dh等填写刚刚建立的4个文件;取消push "redirect-gateway def1 bypass-dhcp"前的注释符号";"可以将客户端的默认路由改为经过server,不过最好不启用这个特性而令客户端自己配置路由。(OpenVPN的配置项较多,请仔细查看说明,不要全信我。)
  客户端还需要client.conf,可由examples/sample-config-files/client.conf修改而来。
  因为有些学校校园网可以免费访问教育网免费地址,所以我写了个[download id="52"]为这些地址(更新到9月)添加路由(经过未连接VPN时的默认路由,仅限Linux),并将默认路由改为经过VPN,请看懂了再用。放在客户端的/etc/openvpn下,client.conf文件末尾加入

script-security 2
up ./addroute_cernet.sh

可以令其在建立连接后自动运行。Windows下的配置兹不详述。

  tinc其实是比OpenVPN历史更悠久的一个VPN解决方案,也是我目前正在使用的方案,相比之下,tinc比OpenVPN占用资源更少,但效率不若OpenVPN,启用压缩后更是大幅下降。原本它的IPv6支持在Windows XP上是跑不起来的,经过我提交bug之后,终于在新版本中跑起来了。
  Linux下的配置过程可见Documentstinc manual,Windows下直接按Example来就行了。概括地说,每个机器需要一个tinc.conf文件(tinc运行需要的参数都在里面),一个tinc-up文件(配置IP地址和路由,Windows不使用),一套host文件(相当于OpenVPN的证书)。由于有OpenVPN的C/S结构先入为主,配置TInc时走了不少弯路。这里区别两种概念:OpenVPN的服务器端是VPN的核心节点;而tinc并不区分服务器端和客户端,它的本意是连接两个子网。我们把“服务器端”当作网关,就要令服务器的子网是0.0.0.0/0(即全世界),而令客户端的子网是x.x.x.x/32(即只有一台机器)。
  tinc.conf大概将是这个样子:

Name = oldtai
ConnectTo = bjork
Device = /dev/net/tun
AddressFamily = ipv6
Compression = 0

最后两行指明用ipv6连接(不指明仍然不监听IPv6端口,应该是bug),取消压缩。Windows客户端不使用Device一项。
  服务器端与客户端的配置文件并不是相同的。服务器端的tinc.conf没有ConnectTo项,因为服务器不连接其他子网;hosts/下给建立一个代表自身的host文件,其中Address可以不写,Subnet应填写"0.0.0.0/0",再给每个客户端建立一个host文件。客户端tinc.conf要写“ConnectTo 服务器名”,hosts/下只需要代表自身和代表服务器的host文件,代表服务器的host文件中Address要写服务器的外网IP(应该是个IPv6地址),Subnet应填写"x.x.x.x/32"其中"x.x.x.x"是服务器在VPN内的IP。
  tinc没有OpenVPN那样的DHCP支持,需要在tinc-up脚本中用"ifconfig $INTERFACE x.x.x.x netmask 255.255.255.0"配置IP。在客户端,x.x.x.x应该与host文件中的Subnet指定的IP相同;在服务器端则是与客户端的代表服务器的host文件中的Subnet相同。上面添加教育网免费地址路由的[download id="52"]可以合并入tinc-up,不过最后一行的$1应改为$INTERFACE。

  其他的问题如isatap隧道、tun设备、iptables、NAT等兹不详述。其要点在于加载tun模块(/etc/modules),NAT(iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE)。整套方案的基础是IPv6网络无限制,将来IPv6普及之后,可用性不明。目前遗留的问题包括在Windows上自动添加路由、isatap相关的配置等。