遇到的问题
有一个异地组网的需求,也就是说需要搭建VPN进行异地组网,常见的PPTP和L2TP由于某些特殊原因,不得不抛弃不用,重新选择新的协议,思科的AnyConnect基于SSL加密,可以自定义通信的端口号,是个不错的选择,部署了兼容的开源方案ocserv作为服务器,用了一段时间,感觉也很稳定。但是ocserv默认的plan密码只能设置用户名和密码,客户端的IP地址池在ocserv.conf中定义,不能像L2TP和PPTP这些基于PPP拨号获取IP的协议一样指定客户端获取的IP地址,客户端获取的IP地址是随机的,这样一来对于终端用户远程访问很方便,但是对于多站异地组网就很麻烦了,给反向添加路由条目带来了很大的麻烦。
假定有两个站点A(10.1.1.1/24)和B(10.2.2.1/24),A作为VPN服务器,VPN接口网络为192.168.240.1/24,当使用L2TP等基于PPP拨号的协议组网时,由于ppp可以指定用户的ip地址,就可以直接添加静态路由就可以了。如B站点使用用户site_b链接A站点的服务器,指定客户端IP为192.168.240.2,那么在A站点和B站点各加一条静态路由就可以实现A,B互通了:
路由器A:
[root@route-A ~]# route add -net 10.2.2.0 netmask 255.255.255.0 gw 192.168.240.2
路由器B:
[root@route-B ~]# route add -net 10.1.1.0 netmask 255.255.255.0 gw 192.168.240.1
但是ocserv的配置文件不能指定客户端的ip,添加对端路由时就很难受。
基本解决方案
ocserv提供了一个occtl的管理工具可以使用occtl show users 命令查看当前已经连接的用户和客户端
[root@route-A ~]# occtl show users id user vhost ip vpn-ip device since dtls-cipher status 1399 site_b default 61.53.53.53 192.168.240.9 vpns0 7m:22s (no-dtls) connected
像这样的,用occtl命令能得到客户端的ip地址,在用akw命令剥离出ip地址,再进行路由的添加,可以使用cron定时检查当前连接的客户端信息,信息判断是否要添加路由。以下是我用过的路由添加脚本,在这里贴出来供朋友们参考:
#!/bin/bash setRoute(){ TARGET_USER=$1 TARGET_ROUTE=$2 TARGET_MASK=$3 echo "--------------------------------------------------------------------" echo "|" $(date) "Checking for "$TARGET_USER"@"$TARGET_ROUTE ROUTE_TO_TARGET=$(route -n | grep $TARGET_ROUTE) if [[ -z "$ROUTE_TO_TARGET" ]];then echo "| Route NOT esixt!Checking vpn ststus and add route..." OC_USERS=$(occtl show users) OC_USERS_COUNT=$(occtl show users | wc -l | awk '{print $1}') USER_ONLINE='False' for i in $(seq 2 $OC_USERS_COUNT) do OC_USER=$(occtl show users|sed -n "$i"p) USER_NAME=$(echo $OC_USER | awk '{print $2}') USER_IP=$(echo $OC_USER | awk '{print $5}') USER_DEV=$(echo $OC_USER | awk '{print $6}') if [ $USER_NAME = $TARGET_USER ];then if [ $USER_ONLINE = 'False' ];then USER_ONLINE='True' echo "| add route..." route add -net $TARGET_ROUTE netmask $TARGET_MASK gateway $USER_IP dev $USER_DEV echo "| " $(route -n | grep Destination) echo "| " $(route -n | grep $TARGET_ROUTE) echo "| Done!" else echo "| Multiple same users online! not operate!" fi fi done if [ $USER_ONLINE = 'False' ];then echo "| User NOT Online!" fi else #Route exist,compared then update echo "| Route already exists!Checking vpn ststus and update route..." PARE_IP=$(echo $ROUTE_TO_TARGET | awk '{print $2}') PARE_MASK=$(echo $ROUTE_TO_TARGET | awk '{print $3}') PARE_DEV=$(echo $ROUTE_TO_TARGET | awk '{print $8}') OC_USERS=$(occtl show users) OC_USERS_COUNT=$(occtl show users | wc -l | awk '{print $1}') USER_ONLINE='False' for i in $(seq 2 $OC_USERS_COUNT) do OC_USER=$(occtl show users|sed -n "$i"p) USER_NAME=$(echo $OC_USER | awk '{print $2}') USER_IP=$(echo $OC_USER | awk '{print $5}') USER_DEV=$(echo $OC_USER | awk '{print $6}') if [ $USER_NAME = $TARGET_USER ];then if [ $USER_ONLINE = 'False' ];then USER_ONLINE='True' if [[ $PARE_IP != $USER_IP ]] || [[ $PARE_DEV != $USER_DEV ]];then echo "| Update route..." route del -net $TARGET_ROUTE netmask $PARE_MASK dev $PARE_DEV route add -net $TARGET_ROUTE netmask $TARGET_MASK gateway $USER_IP dev $USER_DEV echo "| " $(route -n | grep Destination) echo "| " $(route -n | grep $TARGET_ROUTE) else echo "| Local Router Configuration is correct, no update required." fi else echo "| Multiple same users online! not operate!" fi fi done if [ $USER_ONLINE = 'False' ];then echo "| User NOT Online!" echo "| Delete route while user offline!" route del -net $TARGET_ROUTE netmask $PARE_MASK dev $PARE_DEV fi fi echo "--------------------------------------------------------------------" } setRoute 'site_b' '10.2.2.0' '255.255.255.0'
使用cron定时执行这个脚本就能实现定时检查链路状态并添加和维护到对端站点的路由了,但是由于cron是定时执行,频率太快影响性能,太慢又更新不及时,多少有些不完美。
提高效率
后来在调别的相关业务的时候偶然得知ocserv有一个连接建立后执行脚本和断开连接后执行脚本的配置选项,在ocserv.conf配置文件中,配置完之后会在新连接建立后和连接断开后执行,并且会将相应的用户名,IP地址等信息以变量$IP_REMOTE、$REASON、$USERNAME、$DEVICE提供,所以就对基于cron的脚本进行了改造:
addRoute() { USERNAME=$1 ROUTE_NEXT=$2 ROUTE_DEVICE=$3 case "$USERNAME" in 'site_b') route add -net 10.2.2.0 netmask 255.255.255.0 gateway $ROUTE_NEXT dev $ROUTE_DEVICE *) ;; esac } delRoute() { USERNAME=$1 ROUTE_NEXT=$2 ROUTE_DEVICE=$3 case "$USERNAME" in 'site_b') route del -net 10.2.2.0 netmask 255.255.255.0 gateway $ROUTE_NEXT dev $ROUTE_DEVICE *);; esac } case "$REASON" in connect) addRoute $USERNAME $IP_REMOTE $DEVICE ;; disconnect) delRoute $USERNAME $IP_REMOTE $DEVICE ;; *) ;; esac
在/etc/ocserv/ocserv.conf中配置:
connect-script = /usr/bin/ocserv-script disconnect-script = /usr/bin/ocserv-script
一定要指定IP
如果说其他原因一定要指定ocserv给openconnect客户端指定ip地址的话,也不是不可行,也是在调别的相关业务的时候找到了这个的解决门路。(和前面提到的是一个业务,是OSPF动态路由相关的,没办法,组网越来越大,静态路由已经很难搞了,详细的见下一篇博文会具体介绍)ocserv默认的plan认证方式不支持,但是ocserv支持radius认证,radius可以指定ip地址,也可以根据不同的用户名,匹配下发不同的路由表,这个就很绝了!参考https://github.com/openconnect/ocserv/blob/master/doc/README-radius.md
其中指出了使用Framed-IP-Address指定客户端IP地址,使用Framed-Route可以指定下发给客户端的路由,并且可以指定多条路由,如:
site_b Cleartext-Password := "password@user" Framed-IP-Address := "192.168.194.2", Framed-Route := "192.168.192.0/18", Framed-Route := "10.0.0.0/8"
注意:本方法仅限常见的CentOS,Ubuntu的Linux 服务器系统可以实现,OpenWRT系统中的ocserv包不支持radius(目前我没有研究出来),另外ocserv作者推荐使用radcli库进行radius客户端的连接,其他radius客户端ocserv作者并未测试。
更新:OpenWRT下的ocserv使用radius进行认证的方法已在文章《OpenWRT系统中ocserv不支持使用Radius指定客户端IP的解决方法》中更新。
部署的方法为安装freeradius和radcli
[root@ocserv ~] yum install freeradius radcli -y
编辑/etc/radcli/radiusclient.conf 和/etc/radcli/server中authserver的地址和密码。
修改ocserv.conf使其使用radius进行认证
auth = "radius[config=/etc/radcli/radiusclient.conf,groupconfig=true]"
在/etc/raddb/user中加入用户信息和指定的IP地址、路由信息等。具体搜索 "Openconnect + Radius" 即可。
动态路由
慢慢的,组网的站点从两个发展到了四个了,每次有新的网段加入后,路由调整能把人折磨死,手工的添加管理静态路由已经无法满足现有的网络环境了,所以我尝试了OSPF动态路由协议去让这些站点动态的学习和维护路由,这样一个节点崩掉后其他节点也能自动更换路由绕开这个节点实现网络的自愈,这是手动静态路由所不能达到的。在研究OSPF的过程中,不得不说一句RouterOS真心好用!但是由于我的各个节点多是使用的OpenWRT设备做路由,如果全部节点更换到RouterOS又要购买新的设备,又是一笔不小的开支,只能硬着头皮去折腾和尝试在OpenWRT上跑OSPF协议了,而且是over ocserv的,过程相当蛋疼,欢迎观摩我的下一篇博文《在OpenWrt上部署OSPF进行异地组网的动态路由生成》。
-
« 上一篇:
AIX系统安装yum包管理器,使用bash替换ksh
-
在OpenWrt上部署OSPF进行异地组网的动态路由生成
:下一篇 »
发表于 2022-11-08 下午 07:35:24
问下版主,这个OpenWRT安装Openconnect,端口放开转发已做就是不知道怎么将ocserv跑起来,把那个勾打上都没用。
发表于 2022-11-09 上午 02:57:25
Openconnect是客户端,Ocserv才是服务端哦
发表于 2022-11-09 上午 11:26:48
不好意思说反了,应该是安装ocserv,并且配置好后不知道怎么将ocserv开启并跑起来,把那个勾打上都没用。
发表于 2022-11-09 下午 12:02:05
/etc/init.d/ocserv restart 试试
发表于 2022-11-09 下午 12:45:02
就是这个命令,然后执行完之后就没有然后了,执行完成后IP a还是没有记录
发表于 2022-11-09 下午 12:02:55
如果还起不来,系统日志里面会有你需要的信息。
发表于 2022-11-11 下午 05:24:16
去看看系统日志吧,会有信息打印的
发表于 2022-11-12 下午 04:30:26
问下版主,我如果直接在末端客户端节点上IS-IS动态路由是不是可以不用去管末端地址是否出现变动?毕竟你之前讲到的OSPF,我试过Quagga和Frrouting全部报错,只有IS-IS和BGP可以进到config-router里面。
发表于 2023-03-25 下午 01:46:16
不可以,我测试的是Quagga无法通过OpenConnect的连接广播路由,因为他这个好像是tun还是tap来着的点对点的,支持好像有问题,我后面是在建立了OpenConnect的基础上再打一条GRE隧道才可以交换路由信息,这个都是19.7版本上的测试,后面的新版本有没有解决这个问题我还不清楚,但据我一个朋友说防火墙调一下就可以了。