Linux 内核支持的隧道主要有 IP 隧道、SIT 隧道、GRE 隧道三种,L2TPv3 隧道比较少见,本文将不做介绍。
IP 隧道是一种比较简单的隧道,其原理就是直接在原始的 IP 包之前加入一个新的 IP 报文头指向对端,将原有的整个 IP 包作为新的 IP 包的 Payload。对端收到这个 IP 包之后取出 Payload 部分进一步处理。
由于存在 IPv4 和 IPv6 两种协议,所以 IP 隧道也就对应地产生了四种类型:
IPIP 隧道:将 IPv4 包封装在 IPv4 包中
SIT 隧道:将 IPv6 包封装在 IPv4 包中
IPIP6 隧道:将 IPv4 包封装在 IPv6 包中
IP6IP6 隧道:将 IPv6 包封装在 IPv6 包中
SIT 隧道的功能与原理与 IP 隧道比较接近,这里就姑且把它们归类在一起。GRE 隧道可以视为对 IP 隧道的增强,加入了一些额外的字节以提供 GRE Key 等高级功能,对隧道内传输的报文没有限制,根据外层使用的包的类型可以分为两类:
GRE 隧道:将 IPv4 或者 IPv6 包封装在 IPv4 包中
IP6GRE 隧道:将 IPv4 或者 IPv6 包封装在 IPv6 包中
建立这些隧道需要你拥有能够互相直接 Ping 通的 IP 地址,运营商做了 NAT,没有公网 IP 的用户就没有办法建立一个通往 VPS 的隧道了。由于这些隧道与 IP 地址是绑定的,所以通过 PPPOE 上网,没有固定 IP 的用户会比较麻烦,需要写脚本定时通知远端本次获得的 IP 是什么并创建隧道等等。
创建一个隧道
创建一个用 IPv4 进行封装的隧道需要使用如下命令:
ip tunnel add tun0 mode 隧道类型 remote 远端 IPv4 地址 local 本地 IPv4 地址
比如:
ip tunnel add tun0 mode ipip remote 1.2.3.4 local 6.7.8.9
ip tunnel add tun0 mode sit remote 1.2.3.4 local 6.7.8.9
ip tunnel add tun0 mode gre remote 1.2.3.4 local 6.7.8.9
创建一个用 IPv6 进行封装的隧道需要使用如下命令:
ip -6 tunnel add tun0 mode 隧道类型 remote 远端 IPv6 地址 local 本地 IPv6 地址
比如:
ip tunnel add tun0 mode ipip6 remote 2001::1 local 2400::1
ip tunnel add tun0 mode ip6ip6 remote 2001::1 local 2400::1
ip tunnel add tun0 mode ip6gre remote remote 2001::1 local 2400::1
创建隧道的命令需要在本地和远端分别执行,远端执行时注意要交换 IP 地址。
通过隧道互访
创建隧道接口 tun0 之后,我们需要为其分配 IP 地址,需要按照隧道类型分配对应类型的 IP。
实际上隧道不存在服务器和客户端的概念,为了方便讲解,我们约定远端的机器采取尾数为 1 的 IP 地址,本地的机器采取尾数为 2 的 IP 地址。
为内层是 IPv4 包的 ipip 隧道、ipip6 隧道分配 IPv4 地址可以在本地执行:
ip addr add 10.24.0.2 peer 10.24.0.1 dev tun0
在远端执行同样的命令,注意交换 IP 地址:
ip addr add 10.24.0.1 peer 10.24.0.2 dev tun0
内层 IPv4 使用 peer 选项可以节省添加路由表的步骤,而内层 IPv6 需要手动添加路由表。
为内层是 IPv6 包的 sit 隧道、ip6ip6 隧道分配 IPv6 地址可以在本地执行:
ip -6 addr add fe80:abcd::2/128 dev tun0
ip -6 route add fe80:abcd::1/128 via fe80:abcd::1/128
在远端执行同样的命令,注意交换 IP 地址:
ip -6 addr add fe80:abcd::1/128 dev tun0
ip -6 route add fe80:abcd::2/128 via fe80:abcd::1/128
正式建立连接
使用如下命令即可正式建立连接,所有隧道通用:
ip link set tun0 up
执行到这一步的时候,你应该可以从本地 Ping 或者 Ping6 远端了。
内层是 IPv4 包的 ipip 隧道、ipip6 隧道可以使用:
ping 10.24.0.1
内层是 IPv6 包的 sit 隧道、ip6ip6 隧道可以使用:
ping6 fe80:abcd::1
PKU 校内网络实例
为了搭建一个无需支付国际网关费用即可访问所有网站的网络环境,可以使用 IPIP6 隧道,利用学校提供的 IPv6 网络承载 IPv4 流量。
PKU 校内 静态 IPv6 地址 规则如下:
静态 IPv6 地址 = 校园网地址: 本网段地址:: 本机地址
校园网地址 为2001:da8:201
如果本机的 IPv4 地址为 162.105 开头,则 本网段地址 为 IPv4 地址的第 3 组数字加 1000,如本机 IPv4 地址为 162.105.10.100,则 本网段地址 为 1010。
如果本机的 IPv4 地址为 222.29 开头,则 本网段地址 为 IPv4 地址的第 3 组数字加 1300,如本机 IPv4 地址为 222.29.10.100,则 本网段地址 为 1310。
本机地址 为任意 1-4 位十六进制数,但不得为 1。
IPv6 网关地址 = 校园网地址: 本网段地址::1
某楼的通过网线直连可以获得的 IPv4 地址为 162.105.105.xx,根据上述规则,该楼的用户可以随意选择2001:da8:201:1105:: 开头的任意的某个 IP 作为自己的静态 IPv6 的 IP,注意不要与其他用户已有的 IP 冲突。而 IPv6 网关地址则是2001:da8:201:1105::1
在本案例中,我选择 2001:da8:201:1105::2048 作为路由器的静态 IPv6 地址,eth0 插外网网线,eht1-4 组成 switch0,IP 段 192.168.1.1/24。另外假设 VPS 的 IPv6 地址是2400:8500:1301::99,
为路由器外网网口添加静态 IPv6 地址可以使用命令:
ip -6 addr add 2001:da8:201:1105::2048/64 dev eth0
ip -6 route add ::/0 via 2001:da8:201:1105::1
在路由器上创建 IPIP6 隧道并绑定 IP:
ip -6 tunnel add tun0 mode ipip6 remote 2400:8500:1301::99 local 2001:da8:201:1105::2048
ip addr add 10.24.0.2 peer 10.24.0.1 dev tun0
ip link set tun0 up
在 VPS 上创建 IPIP6 隧道并绑定 IP:
ip -6 tunnel add tun0 mode ipip6 remote 2001:da8:201:1105::2048 local 2400:8500:1301::99
ip addr add 10.24.0.1 peer 10.24.0.2 dev tun0
ip link set tun0 up
此时 10.24.0.1 与10.24.0.2直接已经可以互相 ping 通了。
接下来在路由器上添加路由规则,使路由器上的所有流量从 IPIP6 隧道出去:
ip route replace 0.0.0.0/0 via 10.24.0.1
在 VPS 上添加路由规则,使路由器上的其他 IP 段在 192.168.1.1/24 的设备的数据包的回复通过 IPIP6 隧道回到路由器上:
ip route add 192.168.1.0/24 via 10.24.0.2
最后在 VPS 上修复 mss、mtu 等问题并设置 NAT:
iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
iptables -t nat -A POSTROUTING -o eth0 -s 10.24.0.2 -j MASQUERADE
iptables -t nat -A POSTROUTING -o eth0 -s 192.168.1.0/24 -j MASQUERADE
至此,无需支付国际网关费用即可自由访问全部网站的网络环境就配置好了。
最后是网络结构拓扑图:
2001:da8:201:1105::2048 2400:8500:1301::99
┌────────┐ ┌─────┐
│ Router ◆──────────────────────◆ VPS │
└────◆───┘10.24.0.2 10.24.0.1└─────┘
192.168.1.1 │
│
192.168.1.2 │
┌────◆────┐
│ Macbook │
└─────────┘
在路由器上执行的全部命令:
ip -6 addr add 2001:da8:201:1105::2048/64 dev eth0
ip -6 route add ::/0 via 2001:da8:201:1105::1
ip -6 tunnel add tun0 mode ipip6 remote 2400:8500:1301::99 local 2001:da8:201:1105::2048
ip addr add 10.24.0.2 peer 10.24.0.1 dev tun0
ip link set tun0 up
ip route replace 0/0 via 10.24.0.1
在 VPS 上执行的全部命令:
ip -6 tunnel add tun0 mode ipip6 remote 2001:da8:201:1105::2048 local 2400:8500:1301::99
ip addr add 10.24.0.1 peer 10.24.0.2 dev tun0
ip link set tun0 up
ip route add 192.168.1.0/24 via 10.24.0.2
iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
iptables -t nat -A POSTROUTING -o eth0 -s 10.24.0.2 -j MASQUERADE
iptables -t nat -A POSTROUTING -o eth0 -s 192.168.1.0/24 -j MASQUERADE