有一个 IPv6 环境摆在你面前,然后你发现它需要认证……不过作为一个优秀大学生,与 IPv6 只有一个认证之隔,怎么能阻挡我们进入 IPv6 世界的决心呢~所以用 IPv6 NAT 冲冲冲吧!

写在前面

先说一下,本文是之前尝试在 OpenWRT 使用 IPv6 Passthrough 失败后写的,并不是十分确定是校园网 IPv6 需要认证(因为没有找到别的学校推行 IPv6 认证的资料,而我校网信办必然不会花费时间搞这个),以及大概看了一下,大部分学校应该都是 IPv6 免认证直接上网,所以并不建议使用 IPv6 NAT。

但是,在我使用 IPv6 Passthrough 后,小米手机有时候会连不上 IPv6 (但是有地址),用 IPv6 NAT 时并没有这种情况……不清楚是 MIUI 负优化还是 Android 都有这个问题,有待了解一下。

网络环境

网络:大学校园网 IPv4/IPv6 双栈

路由器:小米路由器3G, MediaTek MT7621芯片

系统版本: OpenWrt 18.06.1, 4.14.63内核

准备

一个刷写了 OpenWrt 系统的路由器。极路由和小米路由器3G都是不错的选择,其他路由器只要 CPU 在 OpenWrt 的硬件支持列表内,理论上都可以刷写。可以 点击这里 查看 OpenWrt 支持的硬件并下载相应的固件。

一个 IPv6 网络。使用 NAT66 的好处就在于,无论你的上游网关是用 DHCPv6 还是 SLAAC 亦或静态地址,只要你有 IPv6 地址,哪怕你分到了一个 /128 的 IPv6 地址,你也能组一个子网。

步骤

1.安装 ip6tables 和 kmod-ipt-nat6

官方版本的 OpenWrt 已经集成了ip6tables,所以执行以下安装命令时会提示“
ip6tables 已存在于root中”

opkg update
opkg install ip6tables kmod-ipt-nat6

opkg update 是每次安装软件前必需的步骤,作用是下载仓库里的软件包信息,每次重启后都必须执行,否则很大概率找不到软件。

2.更改 ULA-Prefix

在 LuCI 中进入 Network -> Interfaces ,你能看到页面下方 Global network options 中的 IPv6 ULA-Prefix (IPv6 ULA 前缀),默认情况下这是一段随机生成的 fd 开头的48位前缀,例如:fde4:8dba:82e1::1/48

LuCI 界面 IPv6 ULA-Prefix

LuCI 界面 IPv6 ULA-Prefix

你只需要把第一位的 f 改为 d ,例如下图,这一步就完成了!具体原因在下面,可以稍后再看。

LuCI 界面 IPv6 ULA-Prefix

LuCI 界面 IPv6 ULA-Prefix

fd00::/8 地址块中的地址是唯一本地地址,这个地址类似于 IPv4 中的私有地址(最典型的例子:192.168.1.123)。如果 Windows 电脑分配到这个地址不会有什么问题,但是 Android 手机如果被分配到唯一本地地址,则所有的网络请求会优先解析 IPv4。这样的话,你只能直接访问 IPv6 的 IP 地址,所有的域名解析都会优先解析为 IPv4 的地址。即使你连接了 IPv6 的 ShadowSocks VPN ,也无法改善这个问题。

为了避免这个情况,只好放弃 ULA 地址重新设置,但是为了避免地址冲突,我们需要根据 IANA 的 IPv6 分配表 选一个没有被使用的地址。可以很容易地发现 d000::/4 就是一段未分配的前缀,而且 OpenWrt 官方也推荐了这个方法,就是使用前16位为 dxxx 形式的 ULA 前缀,例如我所使用的 dde4:8dba:82e1::1/48。

3.更改 /etc/config/dhcp 文件

将 /etc/config/dhcp 文件中的 config dhcp 'lan' 下面的内容更改为:

config dhcp 'lan'
    option interface 'lan'
    option start '100'
    option limit '150'
    option leasetime '12h'
    option dhcpv6 'server'
    option ra 'server'
    option ra_management '1'

或者在  LuCI 中将 Network -> Interfaces ->  LAN -> DHCP Server -> IPv6 Settings 中的 Router Advertisement-Service 设为 server modeDHCPv6-Service 设为 server modeNDP-Proxy 设为 disabled  。这两步操作等价。

LuCI 界面 IPv6 Settings
LuCI 界面 IPv6 Settings

顺便可以将 DNS 设置为 Google IPv6 DNS: 2001:4860:4860::8888 已经暴毙了……

或者我国下一代互联网国家工程中心的公共 DNS: 240c::6666

4.更改 /etc/firewall.user 文件

假设 WAN 对应的接口为 eth0.2 ,则在 /etc/firewall.user 文件中添加以下内容:

ip6tables -t nat -A POSTROUTING -o eth0.2 -j MASQUERADE

5.查找当前网络的 IPv6 网关地址

在 LuCI 的 Network -> Diagnostics 页面,
Traceroute 旁边的下拉框选择 IPv6,执行 Traceroute 操作,获取目前网络的 IPv6 网关地址(即第一跳的地址),假定为 2001:da8:20c:1a06::1 

一般情况下,如果在 Network -> Interfaces 界面看到自己 WAN6 接口的 IPv6 地址是 /64 的话,直接取前64位,最后4位取1,即可得到目前的 IPv6 网关地址。当然最好还是 Traceroute 测一下。

LuCI 界面 Diagnostics
LuCI 界面 Diagnostics

6.为路由器添加默认网关

使用 route -A inet6 add default gw 2001:da8:20c:1a06::1 命令,为路由器添加默认网关。这一步非常重要,不进行的话电脑能获取到 IPv6 地址但是会无法上网。完成之后,连接到路由器的计算机应该就可以正常访问 IPv6 网站了。

但是这条指令是一次性的,每次重启之后都必须执行。 如果要做到路由器开机自动添加该网关,需要在 /etc/hotplug.d/iface/ 下新建一个文件 90-ipv6 ,给予744可执行权限:

90-ipv6 权限
90-ipv6 权限

文件内容如下:

#!/bin/sh
[ "$ACTION" = ifup ] || exit 0
route -A inet6 add default gw 2001:da8:20c:1a06::1

注意替换自己的网关

7.Well Done!

最后重启一下路由器,所有的工作就完成了!你可以访问 test-ipv6.com 网站来确认自己是否已经正确接入了 IPv6 网络。

想说的话

其实 IPv6 NAT 配置起来非常简单,但是毕竟 NAT 有违 IPv6 的本意,所以之前在成功 NAT 了以后又开始尝试 IPv6 Passthrough (IPv6 穿透),即将路由器改造成 IPv4 路由器 + IPv6 交换机。但是将路由器重置十几遍后才发觉貌似不可行……偶然一次和网信办的工作人员交流了一下,了解到 IPv6 校园网虽然不计费不限速,但是也需要认证……只能胃疼地继续用 NAT66 了……现在校园网 IPv6 已经不认证了,直接 IPv6 Passthrough,然后 Shadowsocks + Proxifier 起飞~

遇到的第二个问题就是 步骤2 中的前缀问题,尽管我知道 Android 有只支持 SLAAC 、无法手动配置 IPv6 DNS 等等许多还算影响不大的问题,但是前缀问题真的是导致我又重置了七八遍路由器,最后在引用的知乎专栏中才了解到了解决办法,也怪自己没有认真看官方文档。

当然,这个方法只推荐于 IPv6 需要认证,同时宿舍用路由器上网的大学教育网环境。如果 IPv6 无需认证,或者想在家中使用 IPv6 ,应该直接使用 IPv6 Passthrough (IPv6 穿透) 获取一个 2xxx 开头的全球单播地址,这样做不仅提高网络通信效率,还符合 IPv6 的初衷。

引用&资料