本文由 简悦 SimpRead 转码, 原文地址 juejin.cn

¶0. 前言
在学习 ipsec 过程中,一般都会涉及到 ipsec 的局限性:ipsec 协议是一种点对点协议,不支持组播,也不能保护组播、广播报文。因此 ipsec 协议无法用于音视频会议等场合,此时通常的解决办法是采用 GRE Over IPSec .
给出的解释是:GRE 协议可以封装组播、广播报文,但是无法对业务内容进行加密;而 ipsec 可以对报文进行加密,但是无法封装组播和广播报文。因此将两种协议结合,因而 GRE over IPSec 协议应运而生。 但是我找了很多资料 (其实没有多少),都没有找到为什么 GRE 协议支持封装组播和广播报文,而 ipsec 不行;他们作为点对点协议,为什么 GRE 可以而 IPsec 不行呢?因为没有找到答案,所以不能证实自己的想法正确与否,于是通过搭建 GRE 隧道环境,学习 Linux 内核中 GRE 隧道的操作配置原则,希望能从中得到些许启发。
搭建 GRE 隧道环境实际上是很简单的,因为 Linux 内核已经支持了 GRE 隧道,因此直接在虚拟机 (ubuntu 和 CentOS) 里进行简单的配置即可完成操作。

¶1. Linux 内核支持的隧道类型
目前 Linux 内核已经支持多种隧道类型,包括:IPIP 隧道,GRE 隧道,... 。其余这几个我也没见过。当然除了这几种,还有 ipsec 协议,l2tp 协议,可以的是我目前都还没有用过,实在是暴殄天物,罪过罪过


下面通过搭建两组拓扑环境,来学习 GRE 隧道的基本规则,然后在此基础上分析下 GRE 和 IPSEC 在组播和广播报文封装的表现出不同行为的可能原因 (另写一遍文章喽)。
¶2. GRE 隧道跨 (公) 网连接相同子网地址主机
¶2.1 拓扑环境

家里设备有限,只有一台电脑,还是通过无线网卡来上网的,因此拓扑环境比较寒酸,其实这些并不重要,只需明白我的两台虚拟机 Ubantu 和 CentOS 通过桥接的方式连在一起,网络上可以通讯即可。
现在,我准备将两个地址分别为 10.1.2.1/24、10.1.2.2/24 的两台主机 (假的,只是个 IP 地址而已) 通过 GRE 隧道连接起来进行通讯。原则上这两个地址属于不同的子网中(Ubantu 中的子网和 CentOS 中的子网,只是这两个子网的网段相同仅此而已),无法直接通讯。
¶2.1 ubuntu 配置
首先,我确定了下该虚拟机中是否存在 gre 相关的接口,结果当然是没有了。
1 | root@ubuntu:/home/toney# ifconfig -a |
¶2.1.1 添加 GRE 隧道
ip tunnel add Tunnel-1 mode gre remote 192.168.1.13 local 192.168.1.10
添加 GRE 隧道时, 需要指定隧道的名称,我这里叫做 Tunnel-1; 因为要搭建 GRE 类型隧道,因此 mode 为 gre。 而 GRE 隧道的地址为 192.168.1.13<========>192.168.1.10。
由于是第一次执行此命令,底层实际上安装上了 gre 隧道相关的驱动。用户只有在此基础上才能配置 GRE 隧道,不过,无需担心,内核自动完成。
如果在添加隧道时不指定 remote 和 local 地址,也是可以的,它实际上是只是安装 gre 隧道相关驱动。下面是添加隧道时没有指定 remote 和 local 地址时的结果:
1 | root@ubantu:/home/toney# ip tunnel add Tunnel-1 |
如果输入完整的命令,则会成功添加上 Tunnel-1 隧道:
1 | root@ubantu:/home/toney# ifconfig -a |
¶2.1.2 配置 GRE 隧道接口 IP
ip addr add 10.1.2.1/24 dev Tunnel-1
或者
ifconfig Tunnel-1 10.1.2.1/24
从添加隧道结果来看,Tunnel-1 接口虽然已经成功添加,但是处于 down 状态,此外也没有 IP 地址。 不,等等,那我们在添加隧道时指定的 remote 和 local 是什么呢?
它是经过 GRE 隧道封装后的报文 IP 地址,但是针对什么报文进行封装,目前我们尚未配置。
配置此接口 IP 的目的是:为了确定哪些报文需要进入 GRE 接口,然后进行隧道封装。为什么需要添加 IP 呢? 因为我们是通过路由将报文引入到 Tunnel-1 接口的, 如果不填 IP,那么我路由的下一条该写成什么呢, 是吧。

¶2.1.3 激活 GRE 隧道接口 IP
ifconfig Tunnel-1 up
或者
ip link set Tunnel-1 up
至于配置接口 IP 和是否 up 接口,没有什么先后顺序,把他们当做不同的 eth 接口处理即可。

¶2.2 CentOS 配置
CentOS 虚拟机的配置和 Ubantu 的配置完全相同,安照此步骤操作即可。
ip tunnel add Tunnel-1 mode gre local 192.168.1.13 remote 192.168.1.10
ip link set Tunnel-1 up
ip addr add 10.1.2.2/24 dev Tunnel-1
查看配置结果 r 如下:
1 | [root@toney toney]# |
路由表信息如下:

¶2.3 ping 包测试通讯链路
这里有一点需要注意:Linux 系统可能开了 iptables 过滤功能,因此在 ping 时出现了类似 "ICMP host 192.168.1.13 unreachable - admin prohibited, length 116" 信息,详情如下:

百度一下, 在两台虚拟机上都执行如下操作即可:
iptables -F
然后在 ping 包测试,数据可通:


至此,基本 GRE 隧道环境搭建成功。
¶3. GRE 隧道跨 (公) 网连接不同子网地址主机
¶3.1 拓扑环境

目的: 通过 GRE 隧道将 20.1.2.1/24、20.1.3.2/24 两个子网连接起来进行通讯。
¶3.2 Ubantu 配置
¶3.2.1 配置 ens33 子接口 IP
ifconfig eth0:1 192.168.100.1/24
查看接口配置如下:

¶3.2.2 添加另一个 GRE 隧道接口并 up
ip tunnel add Tunnel-2 mode gre local 192.168.100.1 remote 192.168.100.2
ifconfig Tunnel-2 up
¶3.2.3 配置隧道接口 IP
ifconfig Tunnel-2 20.1.2.1/24

¶3.2.4 添加对端子网路由表
由于本端没有对端子网 20.1.3.0/24 的路由,因此需要添加路由,将该网段报文引入到 Tunnel-2 接口,这样便可以通过 GRE 隧道进行封装。
route add -net 20.1.3.0/24 gw 20.1.2.1

¶3.3 CentOS 配置
¶3.3.1 配置 ens33 子接口 IP
ifconfig ens33:1 192.168.100.2/24

¶3.3.2 添加另一个 GRE 隧道接口并 up
ip tunnel add Tunnel-2 mode gre remote 192.168.100.1 local 192.168.100.2
ifconfig Tunnel-2 up
结果如下:

¶3.3.3 配置隧道接口 IP
ifconfig Tunnel-2 20.1.3.1/24
¶3.3.4 添加对端子网路由表
由于本端没有对端子网 20.1.2.0/24 的路由,因此需要添加路由,将该网段报文引入到 Tunnel-2 接口,这样便可以通过 GRE 隧道进行封装。
route add -net 20.1.2.0/24 gw 20.1.3.1

¶3.4 ping 测试链路连通性

