在OpenWrt上部署OSPF进行异地组网的动态路由生成

天锦 发表于 码农也得有格调 分类,标签:

前言

异地组网,各站点下都有不止一个的IP段,规模越来越大,遂即尝试从静态路由迁移到OSPF协议上。使用RouterOS模拟OSPF组网时,鼠标咔嗒咔哒点两下就组网成功了,奈何我的设备都是OpenWRT的系统,实现起来可没模拟那么简单,或者说没有在OSPF上那么简单。可以用坎坷来形容了。

全网搜索OpenWRT跑OSPF协议的资料,只有寥寥几篇如蜻蜓点水一般的文章,获得到了一个有用信息,那就是有一个软件叫Quagga,它是一个路由软件套装包,包含了vtysh为用户提供配置操作的接口,zebra进程与内核进行通信,实现路由条目在内核中的添加和修改,以及ospfd、bgpd等多种路由协议的守护进程,完成实际的路由协议的学习和信息交换。quagga通过这种模块化的方式实现了多种路由协议的集成。所以,那还能咋的,安呗,除了它没别的了。

部署OSPF路由协议

[root@OpenWrt-A ~]# opkg update
[root@OpenWrt-A ~]# opkg install quagga quagga-libospf quagga-libzebra quagga-ospfd quagga-vtysh quagga-zebra

安装完成后需要启用quagga

[root@OpenWrt-A ~]# /etc/init.d/quagga enable
[root@OpenWrt-A ~]# /etc/init.d/quagga start

安装完成后输入vtysh命令进入配置终端(注意#后面的中文为注释,请不要照抄进去)

[root@OpenWrt-A ~]# vtysh
Hello, this is Quagga (version 1.1.1).
Copyright 1996-2005 Kunihiro Ishiguro, et al.
OpenWrt-A# configure terminal    #进入配置终端
OpenWrt-A(config)# router ospf    #配置OSPF路由
OpenWrt-A(config-router)# router-id 10.1.1.1    #指定OSPF路由器ID
OpenWrt-A(config-router)# network 10.1.1.0/24 area 0    #声明本地网络
OpenWrt-A(config-router)# network 192.168.240.0/24 area 0    #声明本地ocserv网络
OpenWrt-A(config-router)# do write    #保存配置

OpenConnect服务器我把它定义为A端,对端站点的客户端定义为B端,A端安装和配置Quagga后,B端同样重复上面的操作,安装和配置Quagga。

按道理来说配好之后就应该与对端正常交换路由信息了,但是不知为何,通过 do show ip ospf neighbor 服务器端看到的永远是Init状态:

OpenWrt-A(config-router)# do show ip ospf neighbor
    Neighbor ID Pri State           Dead Time Address         Interface            RXmtL RqstL DBsmL
10.2.2.1        1 Init/DROther      36.787s 192.168.240.2   vpns0:192.168.194.1      0     0     0

而运行OpenConnect客户端的B端则完全看不到邻居信息:

OpenWrt-B(config-router)# do show ip ospf neighbor
    Neighbor ID Pri State           Dead Time Address         Interface            RXmtL RqstL DBsmL
OpenWrt-B(config-router)#

两边的路由器都放开了防火墙,并且通过以太网接口的网络和邻居的发现和建立都正常,唯独OpenConnect的接口无法完成邻居的建立,折腾了很久,依旧无果。如果有知道是什么原因导致的朋友,也希望能留言告知,不胜感激!

后来换了L2TP的协议进行组网,L2TP的接口也能正常建立邻居关系,鉴于L2TP是明文传输,信息传输不安全,加了IPsec之后,能建立邻居关系,能交换路由信息,能ping通,但是有很多奇奇怪怪的毛病,SSH连接无法正常建立,HTTP的Get请求没问题,POST请求就建立不成等等,相当蛋疼。而且L2TP的端口是死的,有的节点的运营商还有封1701端口的情况,还得回到OpenConnect的方案上……哎,又回到了最初的起点~

GRE

GRE隧道相当建立了一个二层的隧道,也能跑广播,自然也能跑路由协议,GRE有GRE over Ipsec,那能不能over openconnect呢?!先建立一个OpenConnect的三层的点对点隧道,再在里面跑GRE隧道,虽然套了两层,效率下降了一点,但起码能用了。

[root@OpenWrt-A ~]# opkg install gre

假定ocserv的ip的192.168.240.1/32,OpenConnect客户端拿到的IP是192.168.240.2/32(OpenWRT中的ocserv无法给客户端指定一个静态IP,这里我先假定是固定的,实际随机IP的解决方案后面会提),GRE隧道使用一个192.168.241.0/30的一个包含2个可用IP的网络。(注意这网络与/31的两点通信不同,该网络有一个广播地址192.168.241.3)A端用192.168.241.1/30,B端用192.168.241.2/30,当OpenConnect连接建立后,可以用以下命令创建一个GRE隧道,这个GRE隧道的流量会通过OpenConnect的连接进行传输

[OpenWRT-A ~]# ip tunnel add gre-site-b mode gre remote 192.168.240.2 local 192.168.240.1
[OpenWRT-A ~]# ip addr add 192.168.241.1/30 dev gre-site-b
[OpenWRT-A ~]# ip link set gre-site-b up

B端:

[OpenWRT-B ~]# ip tunnel add gre-site-a mode gre remote 192.168.240.1 local 192.168.240.2
[OpenWRT-B ~]# ip addr add 192.168.241.2/30 dev gre-site-a
[OpenWRT-B ~]# ip link set gre-site-a up

在各端声明192.168.241.0/30这个网段,顺便取消之前声明的OpenConnect的网段192.168.240.0/24

[root@OpenWrt-A ~]# vtysh
Hello, this is Quagga (version 1.1.1).
Copyright 1996-2005 Kunihiro Ishiguro, et al.
OpenWrt-A# configure terminal
OpenWrt-A(config)# router ospf
OpenWrt-A(config-router)#  no network 192.168.240.0/24 area 0
OpenWrt-A(config-router)# network 192.168.241.0/30 area 0
OpenWrt-A(config-router)# do write

 B端:

[root@OpenWrt-B ~]# vtysh
Hello, this is Quagga (version 1.1.1).
Copyright 1996-2005 Kunihiro Ishiguro, et al.
OpenWrt-B# configure terminal
OpenWrt-B(config)# router ospf
OpenWrt-B(config-router)#  no network 192.168.240.0/24 area 0
OpenWrt-B(config-router)# network 192.168.241.0/30 area 0
OpenWrt-B(config-router)# do write

这样一来,就能够看见A和B的邻居关系建立成功了。

Exstart

在调试期间,偶然出现了两边的OSPF路由器都卡在了Exstart状态,原因是接口的MTU值问题,以太网链路正常情况下MTU值是1500,当OpenConnect在以太网上跑的时候,减去OpenCOnnect协议包头的长度,OpenConnect创建的链路最大MTU就变成了1472,同样的,如果GRE跑在以太网上,最大MTU是1476,也就是1500减去GRE协议的包头长度。但是,我们这次是套跑,在以太网上跑OpenConnect,在套跑的OpenConnect中套跑GRE,所以GRE的MTU值应该是1500-OpenConnect协议包头长度-GRE协议包头长度 = 1448!如果先建立的OpenCOnnect连接后建立了GRE连接的化,GRE会自动寻找底层设备的MTU值并计算自己的合适的MTU值,也就是1448,但是当先建立GRE隧道,没有建立OpenConnect隧道时,GRE协议会直接拿以太网的1500去计算最大MTU值,当两端MTU值不同时,OSPF协议默认就不进行下一步的路由信息交换了,也就卡在了Exstart中。不合适的MTU会造成网络的效率低下,虽然可以使用mtu-ignore忽略这个问题,强制进行路由交换,但是不建议这么做,保证GRE隧道后于OpenConnect隧道建立,让系统自动设置成正确合适的MTU值才是优解。

以不变应万变

前面说了,OpenConnect客户端拿到的IP的随机的,OpenWRT的ocserv不支持radius认证指定客户端IP,那怎么让每次建立的连接都能正确的建立GRE隧道呢?

在ocserv.conf配置文件中有一个连接建立后执行脚本和断开连接后执行脚本的配置选项,,配置完之后会在新连接建立后和连接断开后执行,并且会将相应的用户名,IP地址等信息以变量$IP_REMOTE、$REASON、$USERNAME、$DEVICE提供,写一个脚本就行了,在新连接建立时执行就行了:

addGRE() {
    USERNAME=$1
    ROUTE_NEXT=$2
    ROUTE_DEVICE=$3
    case "$USERNAME" in
        'site_b')
            ip tunnel add gre-site-b mode gre remote $ROUTE_NEXT local 192.168.240.1
            ip addr add 192.168.241.1/30 dev gre-site-b
            ip link set gre-site-b up
            ;;
        *);;
    esac
}
delGRE() {
    USERNAME=$1
    ROUTE_NEXT=$2
    ROUTE_DEVICE=$3
    case "$USERNAME" in
        'site_b')
            ip tunnel del gre-site-b ;;
        *);;
    esac
}
case "$REASON" in
    connect)
        addGRE $USERNAME $IP_REMOTE $DEVICE ;;
    disconnect)
        delGRE $USERNAME $IP_REMOTE $DEVICE ;;
    *);;
esac


在/etc/ocserv/ocserv.conf中修改配置以启用该脚本

connect-script = /usr/bin/ocserv-script
disconnect-script = /usr/bin/ocserv-script

在B端,OpenWRT有端口热插拔事件,当有热插拔事件产生时会执行/etc/hotplug.d/iface/下面的脚本,那么当OpenConnect连接建立后,创建这个GRE隧道就行了。脚本参考如下

新建脚本:

[root@OpenWRT-B ~]# touch /etc/hotplug.d/iface/30-ocserv-site-a-up
[root@OpenWRT-B ~]# chmod +x /etc/hotplug.d/iface/30-ocserv-site-a-up
[root@OpenWRT-B ~]# touch /etc/hotplug.d/iface/30-ocserv-site-a-down
[root@OpenWRT-B ~]# chmod +x /etc/hotplug.d/iface/30-ocserv-site-a-down

ifup对应内容如下:

#!/bin/bash
[ "$ACTION" = ifup ] || exit 0
[ "$INTERFACE" = site-a ] || exit 0
ClientIP=$(ip addr| grep $DEVICE | grep 192.168. | awk '{print $2}' | awk -F '/' '{print $1}')
ip tunnel add gre-site-a mode gre remote 192.168.240.1 local $ClientIP
ip addr add 192.168.241.1/30 dev gre-site-a
ip link set gre-site-a up

ifdown对应内容如下:

#!/bin/bash
[ "$ACTION" = ifdown ] || exit 0
[ "$INTERFACE" = site-a ] || exit 0
ip tunnel del gre-site-a

至此,GRE over OpenConnect完成,但整个工程还没结束,还有重要的一环那就是防火墙还没弄。

防火墙

建立的这个GRE隧道要和本地的LAN在一个防火墙zone中,或者允许ip包的转发,我目前临时的解决方法是关掉防火墙(因为我的OpenWRT是子路由,与互联网连接的是其他路由器负责,关了防火墙没什么大碍,但如果是主网关是定然不行的)OpenWRT的命令行下设置一个接口到防火墙的lan区域的方法我暂时还没有找到,未完待续吧。