在 Linux 里面的 tunnel 共分三类﹐即 IP in IP tunneling﹑ GRE tunneling﹑以及核心以外的 tunnels (例如﹕PPTP)。
Tunnels 可以用来做一些非比寻常的酷玩意。不过﹐如果设定不慎﹐也会将事情弄得一塌糊涂。如果您并非 胸有成竹﹐那就千万不要将您的预设网关指向 tunnel 设备。还有﹐tunneling 也会增加额外的 overhead﹐因为它需要额外的 IP 标头(header)。一般而言﹐每一个封包大概 20 byte 左右﹐这样﹐一个正常的网路封包体积 (MTU) 会是 1500 bytes﹐但如封包果经 tunnel 传送﹐却只有 14800 byte 而已。这其实也不算是什么问题﹐但是当您有机会用 tunnels 来连接大型网路的时候﹐请务必检查 IP 封包的碎片和重组(fragmentation/reassembly)细节。当然啰﹐建立 tunnel 的话﹐最好是从 tunnel 的两端同时著手﹐双管齐下。
此类 tunneling 技术其实在 Linux 里已行之有年了。它需要两个核心模块﹕ipip.o 和 new_tunnel.o。
比方说﹐您有 3 个网路﹕A 和 B 皆为内部网路﹐而透过网路 C (或曰 Internet) 将两者连接起来。这样﹐我们的网路 A 会是如此﹕
network 10.0.1.0
netmask 255.255.255.0
router 10.0.1.1
接网路 C 的网关位址为 172.16.17.18。
而网路 B 则这般﹕
network 10.0.2.0
netmask 255.255.255.0
router 10.0.2.1
接网路 C 的网关位址为 172.19.20.21 。
对网路 C 而言﹐我们假设它能够双向的将网路 A 和 B 之间的封包送递对方。您甚至可以用 Internet 啦。
好了﹐然后您要做的事情是﹕
首先﹐确定所有模块都装好了﹕
insmod ipip.o
insmod new_tunnel.o
然后﹐在网路 A 的 router 上﹐这样做﹕
ifconfig tunl0 10.0.1.1 pointopoint 172.19.20.21
route add -net 10.0.2.0 netmask 255.255.255.0 dev tunl0
然后在网路 B 的 router 上﹕
ifconfig tunl0 10.0.2.1 pointopoint 172.16.17.18
route add -net 10.0.1.0 netmask 255.255.255.0 dev tunl0
完成后﹐将 tunnel 暂时关闭﹕
ifconfig tunl0 down
弹指间﹐就这样搞定了。然而﹐您不能透过 IP-in-iP tunnel 传送广播或 IPv6 信息。您刚才将两个本来不能相互沟通的 IPv4 网路连接起来了﹐然仅此而已。基于兼容考量﹐此程序码由来已久﹐因而逆溯至 1.3 版核心皆兼筹并顾。据我所知﹐ Linux 之 IP-in-IP tunneling 并不能在其它的作业系统或 router 上工作。然而它短小精悍﹐实属首选﹐除非您考虑用 GRE。
GRE 是一个原本由 Cisco 开发的 tunneling 协定﹐较于 IP-in-IP tunneling﹐它略为能耐一些。例如﹐您能够透过 GRE tunnel 传送 multicast 和 IPv6 信息。
在 Linux 里﹐您得借助 ip_gre.o 模块。
不如先让我们将 IPv4 tunneling 做起来吧﹕
比方说﹐您有 3 个网路﹕A 和 B 皆为内部网路﹐而透过网路 C (或曰 Internet) 将两者连接起来。
关于网路 A ﹐如下﹕
network 10.0.1.0
netmask 255.255.255.0
router 10.0.1.1
在网路 C 上的 router 位址为 172.16.17.18。
然后让我们称这个网路为 neta (好了﹐万事起头难)。
然后﹐关于网路 B﹕
network 10.0.2.0
netmask 255.255.255.0
router 10.0.2.1
在网路 C 上的 router 位址为 172.19.20.21。
然后让我们称这网路为 netb 好了(革命尚未成功﹐同志仍需努力)。
对网路 C 而言﹐我们假设它能够双向的将网路 A 和 B 之间的封包送递对方。至于何以然及何所以然﹐则非我们所要操心的。
接下来﹐在网路 A 的 router 上﹐您如此做﹕
ip tunnel add netb mode gre remote 172.19.20.21 local 172.16.17.18 ttl 255
ip link set netb up
ip addr add 10.0.1.1 dev netb
ip route add 10.0.2.0/24 dev netb
这里﹐我们不妨研究一下。在第一行里面﹐我们新增了一个 tunnel 设备﹐称之为 netb (显而易见﹐因为这正是吾之所欲也)。再来﹐我们让它使用 GRE 协定(mode gre)﹐其硬件位址为 172.19.20.21 (于另一端的 router)﹐这样我们的 tunneling 封包将从 172.16.17.18 从出(您的 router 在网路 C 上可以具有好几个 IP 位址﹐并由您决定用哪一个来做 tunneling)﹐而且﹐封包的 TTL 栏位被设定为 255 (ttl 255)。
第 2 行我们将这个设备启动起来。
在第 3 行﹐我们为新增的界面 netb 设定一个位址为 10.0.1.1。用这个在小网路上也未尝不可﹐只是当您踏上采金旅程之际﹐您或需用其它 IP 范围来给 tunneling 界面就是了(例如在此范例中﹐您可以使用 10.0.3.0)。
在第 4 行﹐我们为网路 B 设定好 router。请留意﹐此处使用的 netmask 表示法并不一样。如果您不太了解其意所在﹐可以这样来理解﹕将 netmask 换算为二进位(binary)﹐然后数一数有多少个 1 就是了。如果您连这个也不会﹐万一又想知道﹐那就这样强记即可﹕255.0.0.0 是 /8﹑255.255.0.0 是 /16﹑还有 255.255.255.0 是 /24﹑而 255.255.253.0 则是 /23。
够了真是的﹐还是让我们看看网路 B 的 router 吧。
ip tunnel add neta mode gre remote 172.16.17.18 local 172.19.20.21 ttl 255
ip link set neta up
ip addr add 10.0.2.1 dev neta
ip route add 10.0.1.0/24 dev neta
假如您要拿掉 router A 上的 tunnel﹐则﹕
ip link set netb down
ip tunnel del netb
当然﹐您也可以替 router B 将 netb 换成 neta。
GRE tunnels 目前所选用的 tunneling 类型。它已成标准并且也被广泛的移植到 Linux 社群之外﹐诚是美事一桩。
在核心之外﹐还有成打形形色色的 tunneling 实作﹐绝非夸张之谈。其中表表者非 PPP 和 PPTP 莫属﹐然而其它的也为数众多 (有的为专属的﹐有的是保密的﹐有的甚至不是使用 IP)﹐不过﹐这些实在超过本 HOWTO 的范畴了。