本文由 简悦 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 root@ubuntu:/home/toney ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.1.10 netmask 255.255.255.0 broadcast 192.168.1.255 inet6 2409:8a00:18e9:810:141:383c:ac6f:8b11 prefixlen 64 scopeid 0x0<global> inet6 2409:8a00:18e9:810:f8dd:500e:b1a:463b prefixlen 64 scopeid 0x0<global> inet6 fe80::8e84:574c:7a8b:440a prefixlen 64 scopeid 0x20<link> ether 00:0c:29:fb:db:ad txqueuelen 1000 (Ethernet) RX packets 3581 bytes 1030105 (1.0 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 1177 bytes 114532 (114.5 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 160 bytes 12920 (12.9 KB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 160 bytes 12920 (12.9 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 复制代码
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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 root@ubantu:/home/toney cannot determine tunnel mode (ipip, gre, vti or sit) root@ubantu:/home/toney ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.1.10 netmask 255.255.255.0 broadcast 192.168.1.255 inet6 2409:8a00:18e9:810:141:383c:ac6f:8b11 prefixlen 64 scopeid 0x0<global> inet6 2409:8a00:18e9:810:200d:99e2:4f3d:cb6f prefixlen 64 scopeid 0x0<global> inet6 fe80::8e84:574c:7a8b:440a prefixlen 64 scopeid 0x20<link> ether 00:0c:29:fb:db:ad txqueuelen 1000 (Ethernet) RX packets 5038 bytes 5896155 (5.8 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 2744 bytes 309264 (309.2 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 164 bytes 15044 (15.0 KB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 164 bytes 15044 (15.0 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 root@ubantu:/home/toney add tunnel "gre0" failed: File exists root@ubantu:/home/toney ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.1.10 netmask 255.255.255.0 broadcast 192.168.1.255 inet6 2409:8a00:18e9:810:141:383c:ac6f:8b11 prefixlen 64 scopeid 0x0<global> inet6 2409:8a00:18e9:810:200d:99e2:4f3d:cb6f prefixlen 64 scopeid 0x0<global> inet6 fe80::8e84:574c:7a8b:440a prefixlen 64 scopeid 0x20<link> ether 00:0c:29:fb:db:ad txqueuelen 1000 (Ethernet) RX packets 5097 bytes 5900501 (5.9 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 2766 bytes 311496 (311.4 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 erspan0: flags=4098<BROADCAST,MULTICAST> mtu 1450 ether 00:00:00:00:00:00 txqueuelen 1000 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 gre0: flags=128<NOARP> mtu 1452 unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 1000 (UNSPEC) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 gretap0: flags=4098<BROADCAST,MULTICAST> mtu 1462 ether 00:00:00:00:00:00 txqueuelen 1000 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 164 bytes 15044 (15.0 KB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 164 bytes 15044 (15.0 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 root@ubantu:/home/toney root@ubantu:/home/toney ip_gre 28672 0 ip_tunnel 24576 1 ip_gre gre 16384 1 ip_gre root@ubantu:/home/toney 复制代码
如果输入完整的命令,则会成功添加上 Tunnel-1 隧道:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 root@ubantu:/home/toney Tunnel-1: flags=144<POINTOPOINT,NOARP> mtu 1476 unspec C0-A8-01-0A-00-00-00-87-00-00-00-00-00-00-00-00 txqueuelen 1000 (UNSPEC) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.1.10 netmask 255.255.255.0 broadcast 192.168.1.255 inet6 2409:8a00:18e9:810:141:383c:ac6f:8b11 prefixlen 64 scopeid 0x0<global> inet6 2409:8a00:18e9:810:200d:99e2:4f3d:cb6f prefixlen 64 scopeid 0x0<global> inet6 fe80::8e84:574c:7a8b:440a prefixlen 64 scopeid 0x20<link> ether 00:0c:29:fb:db:ad txqueuelen 1000 (Ethernet) RX packets 5745 bytes 5947674 (5.9 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 2965 bytes 329731 (329.7 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 erspan0: flags=4098<BROADCAST,MULTICAST> mtu 1450 ether 00:00:00:00:00:00 txqueuelen 1000 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 gre0: flags=128<NOARP> mtu 1452 unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 1000 (UNSPEC) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 gretap0: flags=4098<BROADCAST,MULTICAST> mtu 1462 ether 00:00:00:00:00:00 txqueuelen 1000 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 169 bytes 15509 (15.5 KB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 169 bytes 15509 (15.5 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 复制代码
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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 [root@toney toney]# [root@toney toney]# [root@toney toney]# ifconfig Tunnel-1 Link encap:UNSPEC HWaddr C0-A8-01-0D-FF-FF-90-6D-00-00-00-00-00-00-00-00 inet addr:10.1.2.2 P-t-P:10.1.2.2 Mask:255.255.255.0 UP POINTOPOINT RUNNING NOARP MTU:1476 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 b) TX bytes:0 (0.0 b) eth0 Link encap:Ethernet HWaddr 00:0C:29:DA:34:3C inet addr:192.168.1.13 Bcast:192.168.1.255 Mask:255.255.255.0 inet6 addr: 2409:8a00:18e9:810:20c:29ff:feda:343c/64 Scope:Global inet6 addr: fe80::20c:29ff:feda:343c/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:3571 errors:0 dropped:0 overruns:0 frame:0 TX packets:781 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:236685 (231.1 KiB) TX bytes:71021 (69.3 KiB) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:4 errors:0 dropped:0 overruns:0 frame:0 TX packets:4 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:240 (240.0 b) TX bytes:240 (240.0 b) 复制代码
路由表信息如下:
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 测试链路连通性