使用 HE 的免费 6in4 隧道配合 VPS 为家里提供 IPv6 服务


一、前言

听说最近国内在大力推动 IPv6 网络的建设。

不过我感觉要到猴年马月家里的宽带才会原生支持 IPv6,而且就算支持了也应该是完全没有自由的“内网 IPv6 ”吧。

当两年前家里的宽带还有公网 IP 的时候,我也试过通过 HE 的 6in4 隧道为家里提供 IPv6 连接,但效果非常差,丢包很厉害。

由于我当时 Linux 及网络方面的知识懂得非常少,并且也不是很了解科学上网的原理,最后这件事也就不了了之了……

本文将介绍如何使用国外 VPS 作为跳板来让不支持 IPv6 的家庭宽带接入畅通无阻的 IPv6 互联网。


二、6in4 隧道简介

6in4 隧道通过为 IPv6 数据包额外添加一层 IPv4 报头,来实现 IPv4 海洋中 IPv6 孤岛的互联。

6in4 隧道常用于将使用纯 IPv4 公网出口的园区网接入到 IPv6 公网中。6in4 隧道一般在园区网的边界网关上部署。

Tunnel Broker 是由 Hurricane Electric 提供的免费 6in4 隧道服务。

6in4 隧道听起来很好,但它很难适应国内的网络环境。

第一,6in4 隧道要求隧道两端的路径不能有 NAPT 设备。而目前国内的家庭宽带基本上不能满足这个要求。

第二,6in4 隧道默认没有任何加密措施,IPv6 报文在隧道中都是以明文形式传输的。这……你懂的。

所以,要在国内使用 6in4 隧道来接入不受限制的 IPv6 互联网还是要靠国外 VPS。


三、方案设计及说明

说明
• 本方案使用 EVE-NG 进行仿真,并且所有地址都是虚构的。

拓扑图如下:

现在有一台没有接入 IPv6 网络、提供 Shadowsocks 服务的 VPS,需要通过 Tunnel Broker 提供的 6in4 隧道来为 VPS 本身以及家里的内网提供 IPv6 接入。

从 Tunnel Broker 创建的 6in4 隧道主要参数如下:

  • Server IPv4 Address(Tunnel Broker 服务器的 IPv4 地址): 100.1.1.2
  • Server IPv6 Address(VPS 隧道接口的 IPv6 地址): 2001:64:64:1::1/64
  • Client IPv4 Address(VPS 的 IPv4 地址): 200.1.1.2
  • Client IPv6 Address(Tunnel Broker 服务器隧道接口的 IPv6 地址): 2001:64:64:1::2/64
  • Routed /64(可被路由的 /64 网段): 2001:64:64:2::/64(未使用)
  • Routed /48(可被路由的 /48 网段): 2001:48:48::/48

说明
• /48 网段需要在隧道创建之后手动点击网页上的 「Assign /48」才可分配。

VPS 通过 6in4 隧道接入 IPv6 网络并没有什么难度。该方案的难点在于如何在 VPS 和家里的路由器之间建立一条安全的点到点 IPv6 隧道。

VPS 和家里路由器之间的点到点隧道必须满足两点,一是必须使用 TCP 封装(用于穿越 NAPT,并且我这边到 VPS 的 UDP 连接被封杀),二是支持通过 Socks 或 HTTP 前置代理建立连接(不解释)。

OpenVPN 是一个很不错的解决方案,它支持使用 TCP 和前置代理建立隧道。但 OpenVPN 的配置过于复杂,使得我必须去寻找更好的解决方案,如果实在走投无路了才用 OpenVPN。

还好,我发现了 SSH 支持点到点隧道的建立。SSH 使用 TCP 连接,并且支持前置代理,完全能满足要求!好了,就它了!

下面将介绍如何在 VPS 上配置 6in4 隧道、在 VPS 与家里的路由器之间通过 Shadowsocks 建立 SSH 点到点隧道以及让家里接入 IPv6 网络。所有配置完成后,家里的 PC 必须能够自动获取 IPv6 地址和 DNS 服务器,以及使用 IPv6 直接访问 Google DNS 服务器。

说明
• VPS 和家里的路由器均使用 CentOS 7.5.1804 系统(已关闭防火墙和 SELinux)。
• 家里路由器 Shadowsocks 客户端监听的 Socks5 地址为 127.0.0.1,端口为 1080
• 家里的 PC 使用 Windows 7 系统。
• 各设备各接口、网段的地址如拓扑图所示。


四、VPS 的配置

4.1 配置 6in4 隧道

说明
• 如果您的 VPS 使用了内网 IP 地址,则必须确保协议号为 41 的流量能够被 NAT,否则隧道将不可用(Google Cloud 不能用)。

执行以下命令:

cat << EOF > /etc/sysconfig/network-scripts/ifcfg-tun0

请按实际情况以及注释提示修改以下内容,完成后去除 # 号和后面的注释,然后粘贴到命令行窗口中按回车即可。

DEVICE=tun0 # 隧道接口名
TYPE=sit
BOOTPROTO=none
ONBOOT=yes
PHYSDEV=eth0 # 指定 VPS 的外网接口
IPV6INIT=yes
IPV6_AUTOCONF=no
IPV6_DEFROUTE=yes # 将该接口作为 IPv6 默认的出接口
IPV6_PEERROUTES=yes # 同上
IPV6ADDR=2001:64:64:1::2/64 # 填入获取到的 Client IPv6 Address
IPV6_DEFAULTGW=2001:64:64:1::1 # 填入获取到的 Server IPv6 Address
IPV6TUNNELIPV4=100.1.1.2 # 填入获取到的 Server IPv4 Address
EOF

说明
• 如果 tun0 接口已被占用,请自行更换接口名 tun 后面的编号即可。

完成之后执行以下命令来使隧道生效:

systemctl restart network

4.2 允许 SSH 建立隧道连接

执行以下命令:

sed -i 's/^.*PermitTunnel.*$/PermitTunnel yes/' /etc/ssh/sshd_config && \
systemctl restart sshd

4.3 修改 SSH 心跳检测参数

修改该参数可以让服务器及时释放已掉线客户端的隧道连接,从而避免客户端重连时隧道无法建立。

执行以下命令:

sed -i -e 's/^.*ClientAliveInterval.*$/ClientAliveInterval 1/' -e 's/^.*ClientAliveCountMax.*$/ClientAliveCountMax 3/' /etc/ssh/sshd_config && \
systemctl restart sshd

说明
• 该命令能让 SSH 服务器每隔 1 秒向客户端发送心跳包,当连续 3 个心跳包未得到回复时,自动断开 SSH 连接。

4.4 开启 IPv6 转发

执行以下命令:

echo "net.ipv6.conf.all.forwarding=1" >> /etc/sysctl.conf && \
sysctl -p

五、家里路由器的配置

5.1 安装所需软件

yum -y install epel-release && \
yum -y install radvd kea autossh

说明
• radvd 用于向内网主机提供 IPv6 无状态地址自动配置服务。
• kea 用于向内网主机提供 DHCPv6 服务(可选)。
• autossh 用于自动维护与 VPS 的 SSH 连接。之前写过一篇介绍 autossh 的文章,如有需要可参考。

5.2 开启 IPv6 转发

echo "net.ipv6.conf.all.forwarding=1" >> /etc/sysctl.conf && \
sysctl -p

5.3 设置内网接口的 IPv6 地址

请使用 vim 之类的文本编辑器打开 /etc/sysconfig/network-scripts/ifcfg-<内网接口名>。例如这里是 /etc/sysconfig/network-scripts/ifcfg-eth1

打开之后去除所有以 IPV6 开头的行,然后按实际情况修改以下内容并将其添加到文件末尾。

IPV6ADDR=<IPv6 地址>/<前缀长度>
IPV6INIT=yes
IPV6_AUTOCONF=no

说明
• 内网网段必须在 Tunnel Broker 提供的 Routed /64Routed /48 范围内。

例如这里是:

IPV6INIT=yes
IPV6_AUTOCONF=no
IPV6ADDR=2001:48:48:2::1/64

修改完成后保存退出,然后执行以下命令来使配置生效:

systemctl restart network

5.4 配置路由通告

说明
• 路由通告是一种 ICMPv6 报文。它能让开启 IPv6 功能的主机自动配置 IPv6 地址及网关,以实现即插即用。

请使用 vim 之类的文本编辑器打开 /etc/radvd.conf

打开之后清空该文件,然后按实际情况修改以下内容,修改完成之后将其添加到文件中。

interface <内网接口名>
{
    AdvSendAdvert on;
    MinRtrAdvInterval 30;
    MaxRtrAdvInterval 100;
    AdvManagedFlag off;
    AdvOtherConfigFlag on;
    prefix <内网 IPv6 前缀>/<前缀长度>
    {
        AdvOnLink on;
        AdvAutonomous on;
        AdvRouterAddr on;
    };

};

例如这里是:

interface eth1
{
    AdvSendAdvert on;
    MinRtrAdvInterval 30;
    MaxRtrAdvInterval 100;
    AdvManagedFlag off;
    AdvOtherConfigFlag on;
    prefix 2001:48:48:2::/64
    {
        AdvOnLink on;
        AdvAutonomous on;
        AdvRouterAddr on;
    };

};

修改完成后保存退出,然后执行以下命令来开启相关服务并让其开机自启动:

systemctl start radvd && \
systemctl enable radvd && \
systemctl status radvd

执行命令之后如果有出现绿色小点,说明服务已成功启动。

5.5 配置 DHCPv6 服务器(可选)

说明
• 路由通告并不能让主机获取除 IPv6 地址及网关外的其他信息。如果要让主机获取到 IPv6 DNS 服务器信息,必须使用 DHCPv6 服务器。
• 这里的 DHCPv6 服务器仅为主机提供 IPv6 DNS 服务器信息,并不为主机分配地址。这一行为由路由通告报文的 M 位和 O 位控制。
• DHCPv6 服务器使用 UDP 端口 547 来接收客户端的请求。
• 没有必要为了让主机拿到 IPv6 DNS 服务器信息而部署 DHCPv6 服务器,因为目前大部分 IPv4 DNS 服务器都能解析域名的 IPv6 地址。这里配置 DHCPv6 服务器只是为了让方案更完美一些。

请使用 vim 之类的文本编辑器打开 /etc/kea/kea.conf

说明
• 该配置文件使用 JSON 格式(支持注释)。如果文件不符合 JSON 格式将导致 DHCPv6 服务无法启动,请仔细修改。

找到 Dhcp6 部分,在其中 "interfaces": [][] 中填入加上双引号的内网接口名(大约在第 57 行)。例如这里填完后这一行为 "interfaces": ["eth1" ]

然后找到 "subnet6": [...] 部分,在这部分的最末的 ] 后面添加一个 ,(大约在第 102 行),然后新建一个行,接着在这一行中插入以下内容:

说明
• 这里设置为主机分配的 IPv6 DNS 服务器。DNS 服务器我用的是 Google 的 IPv6 DNS,如果不满意可自行更换。

   "option-data": [{
        "name": "dns-servers",
        "data": "2001:4860:4860::8888, 2001:4860:4860::8844"
   }]

修改完成后保存退出,然后执行以下命令来开启相关服务并让其开机自启动:

systemctl start kea-dhcp6 && \
systemctl enable kea-dhcp6 && \
systemctl status kea-dhcp6

执行命令之后如果有出现绿色小点,说明服务已成功启动。

5.6 与 VPS 建立 SSH 点到点隧道

在建立隧道之前,请确保与 VPS 的 SSH 连接是使用公钥进行认证的,并且 VPS 的身份已得到确认。

命令用法

autossh -M 0 -f -w <路由器隧道编号>:<VPS 隧道编号> -o "PubkeyAuthentication=yes" -o "PasswordAuthentication=no" -o "ServerAliveInterval 1" -o "ServerAliveCountMax 10" -o PermitLocalCommand=yes \
-o LocalCommand="ip addr add <路由器隧道接口的 IPv6 地址>/<前缀长度> dev tun<路由器隧道编号>; ip link set tun<路由器隧道编号> up; ip route add ::/0 dev tun<路由器隧道编号>" -o ProxyCommand="nc --proxy-type socks5 --proxy <Socks5 服务的监听地址>:<Socks5 服务的监听端口> %h %p" \
[email protected]<VPS 的 IP 地址> "ip addr add <VPS 隧道接口的 IPv6 地址>/<前缀长度> dev tun<VPS 隧道编号>; ip link set tun<VPS 隧道编号> up; ip route add <内网 IPv6 前缀>/<前缀长度> dev tun<VPS 隧道编号>"

说明
• 路由器与 VPS 之间点到点隧道的网段必须在 Tunnel Broker 提供的 Routed /64Routed /48 范围内。
• 隧道编号必须本地唯一。

例如这里是:

autossh -M 0 -f -w 100:100 -o "PubkeyAuthentication=yes" -o "PasswordAuthentication=no" -o "ServerAliveInterval 1" -o "ServerAliveCountMax 10" -o PermitLocalCommand=yes \
-o LocalCommand="ip addr add 2001:48:48:1::2/64 dev tun100; ip link set tun100 up; ip route add ::/0 dev tun100" -o ProxyCommand="nc --proxy-type socks5 --proxy 127.0.0.1:1080 %h %p" \
[email protected] "ip addr add 2001:48:48:1::1/64 dev tun100; ip link set tun100 up; ip route add 2001:48:48:2::/64 dev tun100"

执行完该命令之后,隧道将由 autossh 自动维护。如果想要断开连接,直接 killall -9 相关的 autossh 以及 ssh 进程即可。

如果想要开机自动建立隧道,直接将以上命令放入 /etc/rc.local 并确保 /etc/rc.local 可执行即可。

5.7 配置 IPv6 防火墙(基于 ip6tables,可选)

由于内网使用的 IPv6 地址都是全球可达的公网地址,所以很有必要设置防火墙来防止内网被攻击。

下面将在路由器上设置一些简单的 IPv6 防火墙规则来阻止公网传入内网及路由器的连接(假设没有配置过 IPv6 防火墙)。

执行以下命令:

cat << EOF > /etc/sysconfig/ip6tables

请按实际情况修改以下内容,完成后粘贴到命令行窗口中按回车即可。

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p ipv6-icmp -j ACCEPT
-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i <内网接口名> -o <路由器隧道接口名> -j ACCEPT
COMMIT
EOF

例如这里是:

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p ipv6-icmp -j ACCEPT
-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth1 -o tun100 -j ACCEPT
COMMIT
EOF

然后执行以下命令来开启 IPv6 防火墙并让其开机自启动:

systemctl start ip6tables && \
systemctl enable ip6tables

六、验证结果

6.1 检查家里路由器的隧道接口

在家里的路由器上执行以下命令:

ip link show tun<路由器隧道编号>

例如这里是:

ip link show tun100

运行结果:

7: tun100: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq state UNKNOWN mode DEFAULT group default qlen 500
    link/none 

如果能看到以上信息,说明与 VPS 的隧道建立成功。

6.2 检查家里路由器的 IPv6 连通性

下面在家里的路由器上 ping 一下 Google 的 IPv6 DNS 服务器。

ping6 -c4 2001:4860:4860::8888

运行结果:

PING 2001:4860:4860::8888(2001:4860:4860::8888) 56 data bytes
64 bytes from 2001:4860:4860::8888: icmp_seq=1 ttl=62 time=3.34 ms
64 bytes from 2001:4860:4860::8888: icmp_seq=2 ttl=62 time=4.41 ms
64 bytes from 2001:4860:4860::8888: icmp_seq=3 ttl=62 time=3.24 ms
64 bytes from 2001:4860:4860::8888: icmp_seq=4 ttl=62 time=6.03 ms

如果能看到以上信息,说明路由器已通过隧道连接到 IPv6 公网。

6.3 检查家里 PC 的 IPv6 连通性

配置完成后,请将 PC 的网卡禁用后再启用以刷新 IPv6 地址。

不出意外的话,可以在网络适配器的详细信息中看到路由器分配的 IPv6 地址以及 IPv6 DNS 服务器。如下图:

然后再 ping 一下 Google 的 IPv6 DNS 服务器看看能不能通。如下图:

能通!这样就已经达到预期效果了。


七、注意事项

  1. 本方案对宽带到 VPS 连接质量的要求较高。如果连接质量无法保证,则 SSH 点到点隧道会频繁掉线重连,这会严重影响正常的上网体验。
  2. 本方案所使用的 IPv6 地址均是全球可达的公有地址。强烈推荐设置 IPv6 防火墙,以防内网受到攻击。
  3. 本文纯属个人学习经验,无法保证完全正确。如有错误请及时提出,谢谢!
  4. 由于网络环境是不断变化的,所以本文所述的 IPv6 现状具有时效性(更新于 2018 年 10 月 29 日)。

发表评论