Linux 隧道
{Back to Index}

Table of Contents

1 隧道技术

所谓隧道就是把下一层(比如 IPv4 层)的包封装到上一层(比如 SSH, HTTP )或者同一层(比如 IPv6 层)的协议中进行传输,从而实现网络之间的穿透。 很明显,这种实现有个前提,那就是,发送端和接收端 必须各有一个解析这种包的程序或者内核模块才能实现正常通信。

由于发送端和接收端都需要知道对端的 IP 地址,如果在隧道的路径上有网络地址转换(NAT),那么隧道就不能正常的工作。

2 SIT (Simple Internet Transition) 1

SIT 是 IPv6 over IPv4 的隧道,可以为没有 IPv6 接入的机器提供 Tunnel Broker 服务。

ip tunnel add ${interface_name} mode sit \
    local ${local_endpoint_address} \
    remote ${remote_endpoint_address}

3 IPIP (IP in IP) 2

IPIP 是把 IP 层封装到 IP 层的一个 tunnel ,看起来似乎是浪费,实则不然。它的作用相当于一个基于 IP 层的网桥。 我们知道,普通的网桥是基于 mac 层的,不需要 IP ,而IPIP 则是通过两端的路由实现一个隧道,把两个本来不通的网络通过点对点的方式连接起来。

IPIP 是最简单的隧道,头部开销最小,但是只能封装 IPv4 单播数据,因此 不支持 OSPF,RIP 和广播。 同一对节点之间 只能建立一条 IPIP 隧道。GRE 和它类似,但功能更强大,支持广播, 因此可以取代 IPIP 。

3.1 实验

3.1.1 网络拓扑

topo_ipip.png

Figure 1: 实验网络拓扑(ipip)

3.1.2 配置

Instance 1:

ip tunnel add ipiptun mode ipip local 172.31.13.79 remote 172.31.11.150
ip l set ipiptun up
ip a add 192.168.1.80/24 dev ipiptun
ip a add 192.168.1.79/24 dev eth1
ip r del 192.168.1.0/24 dev eth1

[root@ip-172-31-13-79 ec2-user]# ip r
default via 172.31.0.1 dev eth0
169.254.169.254 dev eth0
172.31.0.0/20 dev eth0 proto kernel scope link src 172.31.13.79
172.31.0.0/20 dev eth1 proto kernel scope link src 172.31.9.218
192.168.1.0/24 dev ipiptun proto kernel scope link src 192.168.1.80

3.1.3 抓包分析

分别在 eth0ipiptun 上抓取数据包(eth0.pcap, ipiptun.pcap)。

ipiptun_request.png

Figure 2: Echo Request (ipiptun)

ipip_eth0_request.png

Figure 3: Echo Request (eth0)


ipiptun_reply.png

Figure 4: Echo Reply (ipiptun)

ipip_eth0_reply.png

Figure 5: Echo Reply (eth0)

4 GRE 3 , 4

GRE 规定了如何用一种网络协议去封装另一种网络协议的方法。GRE 隧道由两端的源 IP 地址和目的 IP 地址来定义, 允许用户使用 IP 包封装 IP,IPX,AppleTalk 包,并支持全部的路由协议(如 RIP2,OSPF 等)。

不同于 IPIP ,同一对节点之间可以设置 64K 条隧道。5

4.1 实验

4.1.1 网络拓扑

topo.png

Figure 6: 实验网络拓扑(GRE)

4.1.2 配置

  1. 在 instance 1 上创建隧道设备

    ip tunnel add gretun mode gre local 172.31.6.121 ttl 64 remote 172.31.2.240 dev eth0

  2. 启用隧道设备

    ip l set gretun up

  3. 配置 IP

    ip addr add 192.168.1.122/24 dev gretun

  4. 添加路由

    上一步默认会建立一条路由,如果没有则需手动添加 ip r add 192.168.1.0/24 dev gretun

路由信息:

[ec2-user@ip-172-31-6-121 ~]$ ip r
default via 172.31.0.1 dev eth0
169.254.169.254 dev eth0
172.31.0.0/20 dev eth0 proto kernel scope link src 172.31.6.121
192.168.1.0/24 dev gretun proto kernel scope link src 192.168.1.122

在 instance 2 上进行对等的配置:

ip tunnel add gretun mode gre local 172.31.2.240 ttl 64 remote 172.31.6.121 dev eth0
ip l set gretun up
ip addr add 192.168.1.0/24 dev gretun

4.1.3 抓包分析

在 instance 1 上 ping instance 2 ,分别在 eth0gretun 上抓包:(eth0.pcap, gretun.pcap)

tcpdump -i eth0 -w eth0.pcap 'proto gre'
tcpdump -i gretun -w gretun.pcap 'icmp'

gretun_echo_request.png

Figure 7: Echo Request (gretun)

eth0_echo_request.png

Figure 8: Echo Request (eth0)


gretun_echo_reply.png

Figure 9: Echo Reply (gretun)

eth0_echo_reply.png

Figure 10: Echo Reply (eth0)

4.1.3.1 内核的处理过程 6

可以看到,发送过程是很简单的,因为 instance 1 上配置了一条路由规则,凡是发往 192.168.1.0/24 网络的包都要经过 gretun 这个设备, gretun 的驱动程序会在内核中对数据包构造一个新的头,并把对应的外部 IP 地址填进去,最后通过 local 对应的网卡(eth0)发送出去。

当 instance 2 收到从 instance 1 过来的数据包时,它暂时还不知道这个是 GRE 的包, 它首先会把它当作普通的 IP 包处理。因为外部的 IP 头的目的地址是该主机的地址,所以它会接收这个包,并交给上层。 到了 IP 层之后才发现这个包不是 TCP/UDP ,而是 GRE (因为 GRE 定义了一个新的 IP proto 即 IPPROTO_GRE ), 这时内核会把数据转交给 GRE 模块处理。

GRE 模块所做的工作是:剥去外层 IP 头,把“新包”重新交给 IP 栈去处理,像接收到普通 IP 包一样。 ”新包“处理和其它普通的 IP 包就没有什么两样了:根据 IP 头中目的地址转发给相应的网卡。

Footnotes:

Author: Hao Ruan (ruanhao1116@gmail.com)

Created: 2020-03-12 Thu 15:19

Updated: 2021-08-17 Tue 11:23

Emacs 27.1 (Org mode 9.3)