我喜欢tinc,所以都会在防火墙中部署该软件,但是tinc并不支持HA,所以当主用角色(master)[1]在两台防火墙之间漂移的时候,tinc就会懵逼,到底应该在哪台上监听vip?

关于tinc的监听接口

tinc可以设定监听接口,但是无法设定outbound的interface,也就是说来回程的路由不一致[2]这给排错带来困难,特别是有两台构建了HA的防火墙使情况更加复杂。

由于idc机房的安全策略要求级别较高,无法实现1:1 nat映射,因而需要通过tinc实现外网无缝访问内网资源。在nansha idc中,两台proxmox分别跑了shorewall、keepalived和tincd。通过keepalived实现tincd的高可用性。

/etc/keepalived/keepalived.conf
vrrp_sync_group proxmoxCluster {
    group {
        vip_vmbr0
        vip_vmbr199
    }
    notify "/etc/keepalived/change_tincState.sh"
}
vrrp_instance vip_vmbr0 {
    interface vmbr0
    state BACKUP
    virtual_router_id 204
    priority 50
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass nansha
    }
    virtual_ipaddress {
        10.204.255.28
    }
    virtual_ipaddress_excluded {
        10.204.255.29
        10.204.255.30
    }
    nopreempt
    garp_master_delay 1
}

vrrp_instance vip_vmbr199 {
    interface vmbr199
    state BACKUP
    virtual_router_id 99
    priority 50
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass nansha
    }
    virtual_ipaddress {
        192.168.99.1
    }
    nopreempt
    garp_master_delay 1
}
/etc/keepalived/change_tincState.sh
#!/bin/bash

TYPE=$1
NAME=$2
STATE=$3

case $STATE in
    "MASTER") /bin/echo "start tinc for ${STATE}" | /usr/bin/logger -p local6.notice -t change_tincState
              /etc/init.d/tinc restart
              exit 0
              ;;
    "BACKUP") /bin/echo "stop tinc for ${STATE}" | /usr/bin/logger -p local6.notice -t change_tincState
              /etc/init.d/tinc stop
              exit 0
              ;;
    "FAULT")  /bin/echo "stop tinc for ${STATE}" | /usr/bin/logger -p local6.notice -t change_tincState
              /etc/init.d/tinc stop
              exit 0
              ;;
    *)        echo "Unknown state ${STATE} for VRRP ${TYPE} ${NAME}"
              exit 1
              ;;
esac

初始状态:proxmox1为master,proxmox2为backup,vip和tincd均在proxmox1上;

在proxmox1上重启keepalived时(/etc/init.d/keepalived restart),proxmox2成为master,proxmox1成为backup; proxmox2检测到state发生了变化,执行vrrp_sync_group中的notify_master tinc-switcher.sh master脚本; 启动tinc; 删除路由:10.8.0.0/24 via 192.168.99.1 proxmox1由于发生了keepalived重启事件,于是执行了vrrp_instance中的 notify_stop tinc-switcher.sh stop脚本; 停止tinc; 添加路由:10.8.0.0/24 via 192.168.99.1

当proxmox2上重启keepalived时(/etc/init.d/keepalived restart),proxmox1成为master,proxmox2成为backup; proxmox1检测到state发生了变化,执行notify_master tinc-switcher.sh master脚本; 启动tinc; 删除路由:10.8.0.0/24 via 192.168.99.1 proxmox2由于发生了keepalived重启事件,于是执行了notify_stop tinc-switcher.sh stop脚本; 停止tinc; 添加路由:10.8.0.0/24 via 192.168.99.1 当proxmox1发生state变化时,譬如网口down,proxmox1和proxmox2会执行vrrp_sync_group中相应的脚本。分别是 notify_master notify_backup notify_fault

  • notify_stop必须放在vrrp_instance中,否则不起作用。

  • keepalived的文档真是太老了,man keepalived.conf没有notify_stop的说明,只是在2006年的changelog找到简单的一句话。

为了方便同步,proxmox1和proxmox2的/etc/shorewall/nat统一为

#EXTERNAL       INTERFACE       INTERNAL        ALL INTERFACES   LOCAL
10.9.0.194      tun0            192.168.99.29   No               No     # proxmox1
10.9.0.195      tun0            192.168.99.30   No               No     # proxmox2
10.9.0.196      tun0            192.168.99.103  No               No     # wnjsj-2
10.9.0.197      tun0            192.168.99.104  No               No     # wnjsj-3
如何判断是否存在一条特定路由?

假如外网IP地址不开启SSH端口映射,则需要通过tinc连接到两台虚拟防火墙中,而由于tinc是动态在两台防火墙中启停的,所以需要在另外一台防火墙中启用一条静态路由。 1. 当tinc在proxmox 比如说,tinc要在proxmox1和proxmox2中漂移,因而需要在proxmox1和proxmox2中添加和删除以下路由:

"10.9.0.0/16 via 192.168.99.1"

如果能判断当前是否包含这条路由,然后根据情况来添加、删除或修改,这样的处理方式更优雅一些。

# add or change route on master role
EXIST=`ip route show 10.9.0.0/16 | wc -l`
if [ $EXIST -eq 0 ]
then
    sudo ip route add 10.9.0.0/16 dev 192.168.99.1
fi
if [ $EXIST -eq 1 ]
then
    sudo ip route chg 10.9.0.0/16 dev 192.168.99.1
fi

1. 生产环境中往往部署两台防火墙,并利用carp或vrrp来实现双机热备
2. pfsense中称之为sticky route