65.9K
CodeProject 正在变化。 阅读更多。
Home

OpenWRT 路由器中具有 Kill Switch 的弹性高可用性 VPN

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2023年7月16日

CPOL

8分钟阅读

viewsIcon

4126

一种算法和一组脚本,它们在 OpenWRT 路由器上以闭环方式工作,为所有连接的路由器客户端启用弹性高可用性 VPN (openvpn) 连接

引言

本文是我对寻找 OpenWRT 路由器配置以启用连接到它的所有设备的 VPN 的研究结论。我之前曾写过两篇关于同一主题的文章,但本文描述的是最终解决方案,它能在 VPN 连接或禁用时启用紧急开关,并且通过 ping 任意选定的主机来确保 VPN 隧道在中断或不活跃时自动恢复。下面是本文所述脚本所实现的算法流程图。

高可用性 VPN 算法流程图

如上图所示,脚本以闭环方式运行,努力保持 VPN 隧道畅通,以便路由器客户端能够获得高可用性的 VPN 连接,而无需手动重新连接或重启。脚本文件名在图块中给出,方便参考。

紧急开关流程图

上图是紧急开关的流程图,它确保即使在接口重新配置或重启时,紧急开关也能保持激活状态。

前提条件 - 设置路由器

首先,你需要一个已刷写新固件或重置过的 OpenWRT 路由器,OpenWRT 版本为 19.xx 或更高。你需要使用下面的配置设置 LAN 和 WIFI 接口。如果你不熟悉 OpenWRT 路由器的初始设置,请参考 本文 中的“设置 OpenWRT”部分。

网络配置

请确保网络配置文件 /etc/config/network 包含以下条目。粗体行是新增的。

config interface 'lan'
	option device 'br-lan'
	option proto 'static'
	option netmask '255.255.255.0'
	option ipaddr '192.168.3.1'
	list dns '208.67.222.222'
	list dns '208.67.220.220'
	
config interface 'wan'
	option device 'wan'
	option proto 'dhcp'
	option peerdns '0'

config interface 'ovpn'
	option proto 'none'
	option device 'tun0'
	option peerdns '0'
	
config interface 'wifi24'
	option proto 'static'
	option netmask '255.255.255.0'
	list dns '208.67.222.222'
	list dns '208.67.220.220'
	option device 'wlan1'
	option ipaddr '192.168.10.1'

config interface 'wifi50'
	option proto 'static'
	option netmask '255.255.255.0'
	option device 'wlan0'
	list dns '8.8.8.8'
	list dns '8.8.4.4'
	option ipaddr '192.168.11.1'

请确保 DHCP 配置文件 /etc/config/dhcp 包含以下条目。粗体行是新增的。

config dhcp 'lan'
	option interface 'lan'
	option start '100'
	option limit '150'
	option leasetime '12h'
	option dhcpv4 'server'
	list dhcp_option '6,208.67.222.222,208.67.220.220'
	
config dhcp 'wifi24'
	option interface 'wifi24'
	option start '100'
	option limit '150'
	option leasetime '12h'
	list dhcp_option '6,208.67.222.222,208.67.220.220'

config dhcp 'wifi50'
	option interface 'wifi50'
	option start '100'
	option limit '150'
	option leasetime '12h'
	list dhcp_option '6,208.67.222.222,208.67.220.220'

请确保防火墙配置文件 /etc/config/firewall 包含以下条目。粗体行是新增的。

config zone
	option name 'lan'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'
	list network 'lan'
	list network 'wifi24'
	list network 'wifi50'

config zone
	option name 'wan'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option masq '1'
	option mtu_fix '1'
	list network 'wan'
	list network 'ovpn'

启用 WiFi

启用 WiFi 的步骤 在此

完成此初始步骤后,重启路由器,并测试路由器 LAN 和 WiFi 客户端的互联网连接是否正常。配置文件中的接口 IP 地址(例如:192.168.11.1)是任意的,但会在紧急开关脚本中再次使用,因此如果需要,也要相应地更改这些地址。本文还假设有三个客户端接口 lanwlan0wlan1,可以根据需要省略或添加。

安装软件包

脚本需要两个软件包才能运行,请运行以下命令进行安装。

opkg update
opkg install openvpn-openssl pingcheck

上述命令完成后,从 /etc/config/pingcheck 配置文件中删除所有行,以避免意外调用脚本。此配置文件将在后续步骤中再次填充。

所有脚本的文件夹结构

以下是在路由器上创建的所有文件的文件夹结构。每个文件的内容将在下文各节中介绍。请确保创建后所有这些文件都设置为可执行。

步骤 1:紧急开关脚本设置

本节描述的单个热插拔脚本将为所有配置的客户端接口激活紧急开关。实现此目的的方法是为每个接口使用一个单独的自定义路由表,脚本将在其中动态添加或删除路由。这可确保来自接口的流量仅通过有效的 VPN 隧道传输。

添加新的路由表

/etc/iproute2/rt_tables 中添加以下行来添加三个新的路由表。粗体行是新增的。这创建了三个新的路由表,它们将与三个客户端接口相关联。

#
# reserved values
#
128     prelocal
255     local
254     main
253     default
40      custom_lan
39      custom_wlan0
38      custom_wlan1
0       unspec
#
# local
#

添加紧急开关辅助脚本

以下是紧急开关辅助脚本的文件夹结构和脚本内容。请在相同位置创建它们并设置为可执行。

activate-kill-switch-for-interface.sh

创建文件 /etc/openvpn/kill-switch/activate-kill-switch-for-interface.sh 并包含以下内容

#!/bin/sh

interface_cidr=$1
interface_name=$2
interface_gateway=$3
table_name=$4

ip route flush $interface_cidr
ip rule add from $interface_cidr lookup $table_name
ip rule add from all to $interface_cidr lookup $table_name
ip route add $interface_cidr dev $interface_name scope link src $interface_gateway table $table_name
ip route add default via $interface_gateway table $table_name

ip route flush cache

kill-switch-setup-lan.sh

创建文件 /etc/openvpn/kill-switch/kill-switch-setup-lan.sh 并包含以下内容

#!/bin/sh

/etc/openvpn/kill-switch/activate-kill-switch-for-interface.sh 192.168.3.0/24 br-lan 192.168.3.1 custom_lan

kill-switch-setup-wlan0.sh

创建文件 /etc/openvpn/kill-switch/kill-switch-setup-wlan0.sh 并包含以下内容

#!/bin/sh

/etc/openvpn/kill-switch/activate-kill-switch-for-interface.sh 192.168.11.0/24 wlan0 192.168.11.1 custom_wlan0

kill-switch-setup-wlan1.sh

创建文件 /etc/openvpn/kill-switch/kill-switch-setup-wlan1.sh 并包含以下内容

#!/bin/sh

/etc/openvpn/kill-switch/activate-kill-switch-for-interface.sh 192.168.10.0/24 wlan1 192.168.10.1 custom_wlan1

添加热插拔脚本

热插拔脚本将监视接口并通过上述脚本修改路由表中的路由,以确保接口不使用主路由表和常规互联网。您可以在 此处 阅读有关 OpenWRT 热插拔脚本的信息。

99-ifup-wan-interfaces

创建文件 /etc/hotplug.d/iface/99-wan-interfaces 并包含以下内容

#!/bin/sh

wanstateret=`cat /tmp/wanstate`
lanstateret=`cat /tmp/lanstate`
wlan0stateret=`cat /tmp/wlan0state`
wlan1stateret=`cat /tmp/wlan1state`

wanstarted=`echo "$wanstateret" started | awk '{ print ($1 == $2) ? 1 : 0 }'`
lanstarted=`echo "$lanstateret" started | awk '{ print ($1 == $2) ? 1 : 0 }'`
wlan0started=`echo "$wlan0stateret" started | awk '{ print ($1 == $2) ? 1 : 0 }'`
wlan1started=`echo "$wlan1stateret" started | awk '{ print ($1 == $2) ? 1 : 0 }'`

killswitchlanstateret=`cat /tmp/killswitchlanstate`
killswitchwlan0stateret=`cat /tmp/killswitchwlan0state`
killswitchwlan1stateret=`cat /tmp/killswitchwlan1state`

killswitchlanstarted=`echo "$killswitchlanstateret" started | awk '{ print ($1 == $2) ? 1 : 0 }'`
killswitchwlan0started=`echo "$killswitchwlan0stateret" started | awk '{ print ($1 == $2) ? 1 : 0 }'`
killswitchwlan1started=`echo "$killswitchwlan1stateret" started | awk '{ print ($1 == $2) ? 1 : 0 }'`

activatelankillswitch=0
activatewlan0killswitch=0
activatewlan1killswitch=0

if [ "${ACTION}" == "ifdown" ] && [ "${INTERFACE}" = "lan" ]
then
    rm /tmp/killswitchlanstate
fi

if [ "${ACTION}" == "ifdown" ] && [ "${INTERFACE}" = "wifi50" ]
then
    rm /tmp/killswitchwlan0state
fi

if [ "${ACTION}" == "ifdown" ] && [ "${INTERFACE}" = "wifi24" ]
then
    rm /tmp/killswitchwlan1state
fi

if [ "${ACTION}" == "ifup" ] && [ "${DEVICE}" = "wan" ]
then
    echo started > /tmp/wanstate
    if [ $lanstarted -eq 1 ] && [ $killswitchlanstarted -eq 0 ]
    then
        activatelankillswitch=1
    fi
    if [ $wlan0started -eq 1 ] && [ $killswitchwlan0started -eq 0 ]
    then
        activatewlan0killswitch=1
    fi
    if [ $wlan1started -eq 1 ] && [ $killswitchwlan1started -eq 0 ]
    then
        activatewlan1killswitch=1
    fi
fi

if [ "${ACTION}" == "ifup" ] && [ "${DEVICE}" = "br-lan" ]
then
    echo started > /tmp/lanstate
    if [ $wanstarted -eq 1 ] && [ $killswitchlanstarted -eq 0 ]
    then
        activatelankillswitch=1
    fi
fi

if [ "${ACTION}" == "ifup" ] && [ "${DEVICE}" = "wlan0" ]
then
    echo started > /tmp/wlan0state
    if [ $wanstarted -eq 1 ] && [ $killswitchwlan0started -eq 0 ]
    then
        activatewlan0killswitch=1
    fi
fi

if [ "${ACTION}" == "ifup" ] && [ "${DEVICE}" = "wlan1" ]
then
    echo started > /tmp/wlan1state
    if [ $wanstarted -eq 1 ] && [ $killswitchwlan1started -eq 0 ]
    then
        activatewlan1killswitch=1
    fi
fi

if [ $activatelankillswitch -eq 1 ]
then
    echo started > /tmp/killswitchlanstate
    /etc/openvpn/kill-switch/kill-switch-setup-lan.sh
fi

if [ $activatewlan0killswitch -eq 1 ]
then
    echo started > /tmp/killswitchwlan0state
    /etc/openvpn/kill-switch/kill-switch-setup-wlan0.sh
fi

if [ $activatewlan1killswitch -eq 1 ]
then
    echo started > /tmp/killswitchwlan1state
    /etc/openvpn/kill-switch/kill-switch-setup-wlan1.sh
fi

exit 0

创建此热插拔脚本后,重启和接口重启时连接的客户端的互联网将被禁用,请不要惊慌。在完成其余设置并成功建立 VPN 连接后,互联网将开始工作。

步骤 2:高可用性 VPN 脚本设置

添加高可用性文件夹脚本

以下是高可用性 VPN 脚本的文件夹结构和脚本内容。请在相同位置创建它们并设置为可执行。

check-vpn-connection.sh

创建文件 /etc/openvpn/resilient/check-vpn-connection.sh 并包含以下内容

#!/bin/sh

/etc/openvpn/leds/init-complete-led.sh off
/etc/openvpn/leds/connecting-led.sh on

connectedstatus=0
ovpnconnectedstatus=0

i=0
while [ $i -le 30 ]
do
    sleep 1
    i=`expr $i + 1`
    if grep "Initialization Sequence Completed" /tmp/openvpn-main-log; then
        connectedstatus=1
        break;
    fi
done

/etc/openvpn/leds/connecting-led.sh off

if [ $connectedstatus -eq 1 ]
then
    /etc/openvpn/leds/init-complete-led.sh on
    # check pingcheck status for 40 seconds
    i=0
    while [ $i -le 40 ]
    do
        sleep 1
        i=`expr $i + 1
        ovpnstateret=`cat /tmp/pingcheck-ovpnstate`
        ovpnonline=`echo "$ovpnstateret" online | awk '{ print ($1 == $2) ? 1 : 0 }'`
        if [ $ovpnonline -eq 1 ]
        then
            ovpnconnectedstatus=1
            break;
        fi
    done
fi

if [ $connectedstatus -eq 0 ] || [ $ovpnconnectedstatus -eq 0 ]
then
    sh /etc/openvpn/resilient/kill-vpn.sh
fi

kill-vpn.sh

创建文件 /etc/openvpn/resilient/kill-vpn.sh 并包含以下内容

#!/bin/sh
openvpnpid=$(pidof openvpn)
kill $openvpnpid
echo "Killed openvpn"

resilient-vpn-pingcheck-controller.sh

创建文件 /etc/openvpn/resilient/resilient-vpn-pingcheck-controller.sh 并包含以下内容

#!/bin/sh

wanstateret=`cat /tmp/pingcheck-wanstate`
ovpnstateret=`cat /tmp/pingcheck-ovpnstate`

wanonline=`echo "$wanstateret" online | awk '{ print ($1 == $2) ? 1 : 0 }'`
ovpnonline=`echo "$ovpnstateret" online | awk '{ print ($1 == $2) ? 1 : 0 }'`

resilientrunningret=`cat /tmp/resilientrunningstatus`
resilientrunningstatus=`echo "$resilientrunningret" running | awk '{ print ($1 == $2) ? 1 : 0 }'`

if [ $wanonline -eq 1 ]
then
    if [ $ovpnonline -eq 0 ] 
    then
        /etc/openvpn/leds/connected-led.sh off
        if [ $resilientrunningstatus -eq 0 ]
        then
            (sh /etc/openvpn/resilient/start-resilient-vpn.sh >/dev/null 2>&1 )&
            echo running > /tmp/resilientrunningstatus
        fi
        if [ $resilientrunningstatus -eq 1 ]
        then
            sh /etc/openvpn/resilient/kill-vpn.sh
        fi
    fi
    if [ $ovpnonline -eq 1 ] 
    then
        /etc/openvpn/leds/init-complete-led.sh off
        /etc/openvpn/leds/connected-led.sh on
    fi
fi
if [ $wanonline -eq 0 ]
then
    if [ $ovpnonline -eq 1 ] 
    then
        /etc/openvpn/leds/init-complete-led.sh off
        /etc/openvpn/leds/connected-led.sh on
    fi
    if [ $ovpnonline -eq 0 ] 
    then
        sh /etc/openvpn/resilient/stop-resilient-vpn.sh
        echo stopped > /tmp/resilientrunningstatus
    fi
fi

start-openvpn-client.sh

创建文件 /etc/openvpn/resilient/start-openvpn-client.sh 并包含以下内容

dir='/etc/openvpn/configs'
n_files=`/bin/ls -1 "$dir" | wc -l | cut -f1`
rand_num=`awk "BEGIN{srand();print int($n_files * rand()) + 1;}"`
file=`/bin/ls -1 "$dir" | sed -ne "${rand_num}p"`
path=`cd $dir && echo "$PWD/$file"` # Converts to full path.
echo "Chosen file ${path}"
echo "${path}" > /tmp/openvpn-server.log
rm /tmp/openvpn-main-log
openvpn --config ${path} --log /tmp/openvpn-main-log 
        --auth-user-pass /etc/openvpn/credentials --up /etc/openvpn/up.sh 
        --down-pre --down /etc/openvpn/down.sh --route-noexec --dev tun0 
        --persist-local-ip --script-security 2

start-resilient-vpn.sh

创建文件 /etc/openvpn/resilient/start-resilient-vpn.sh 并包含以下内容

#!/bin/sh

rm /tmp/openvpn-main-log
(sh /etc/openvpn/resilient/check-vpn-connection.sh >/dev/null 2>&1 )&
sh /etc/openvpn/resilient/start-openvpn-client.sh

checkscriptpid=$(pgrep -f "sh /etc/openvpn/resilient/check-vpn-connection.sh")
kill $checkscriptpid
/etc/openvpn/leds/connecting-led.sh off

if grep "AUTH_FAILED" /tmp/openvpn-main-log; then
    # Wait for some time to stop overloading  
    /etc/openvpn/leds/auth-failed-led.sh on
    pause_connect_seconds=60
    sleep $pause_connect_seconds
    /etc/openvpn/leds/auth-failed-led.sh off
fi

exec sh /etc/openvpn/resilient/start-resilient-vpn.sh

stop-resilient-vpn.sh

创建文件 /etc/openvpn/resilient/stop-resilient-vpn.sh 并包含以下内容

#!/bin/sh

resilientscriptpid=$(pgrep -f "sh /etc/openvpn/resilient/start-resilient-vpn.sh")
kill $resilientscriptpid
checkscriptpid=$(pgrep -f "sh /etc/openvpn/resilient/check-vpn-connection.sh")
kill $checkscriptpid
sh /etc/openvpn/resilient/kill-vpn.sh
openvpnscriptpid=$(pgrep -f "sh /etc/openvpn/resilient/start-openvpn-client.sh")
kill $openvpnscriptpid
rm /tmp/openvpn-main-log
sh /etc/openvpn/resilient/kill-vpn.sh
/etc/openvpn/leds/connected-led.sh off
/etc/openvpn/leds/connecting-led.sh off
/etc/openvpn/leds/init-complete-led.sh off

添加路由创建脚本

这些脚本由 openvpn 命令和 up.sh 调用,在自定义路由表中创建路由,以便在运行时启用 VPN 互联网访问。down.sh 删除路由。

up.sh

创建文件 /etc/openvpn/up.sh 并包含以下内容。

#!/bin/sh

wanstrifconfig=$(ip -4 -o addr show wan)
wan_cidr=$(echo $wanstrifconfig | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\/[0-9]\{1,\}')

wan_interface_name=wan

vpn_gateway=$route_vpn_gateway
vpn_local=$ifconfig_local
vpn_mask=$ifconfig_netmask
remote_ip=$trusted_ip
device_name=$dev
router_gateway=$route_net_gateway

vpn_interface_cidr=`awk -v val="$vpn_gateway|$vpn_mask" '
function count1s(N){
    c = 0
    for(i=0; i<8; ++i) if(and(2**i, N)) ++c
    return c
}
function subnetmaskToPrefix(input) {
    split(input, inputParts, "|")
    split(inputParts[2], subnetParts, ".")
    split(inputParts[1], mainParts, ".")
  
  if (subnetParts[1] == 0 ) {
        mainParts[1] = 0
    }
    if (subnetParts[2] == 0 ) {
        mainParts[2] = 0
    }
    if (subnetParts[3] == 0 ) {
        mainParts[3] = 0
    }
    if (subnetParts[4] == 0 ) {
        mainParts[4] = 0
    }

     printf "%d.%d.%d.%d/%d", mainParts[1], mainParts[2], 
     mainParts[3], mainParts[4], count1s(subnetParts[1]) + count1s 
}
BEGIN {
    subnetmaskToPrefix(val)
}'`

for vpn_table_name in custom_lan custom_wlan0 custom_wlan1 ; do
    ip route add 0.0.0.0/1 via $vpn_gateway dev $device_name table $vpn_table_name
    ip route add 128.0.0.0/1 via $vpn_gateway dev $device_name table $vpn_table_name
    ip route add $vpn_interface_cidr dev $device_name scope link src 
                 $vpn_local table $vpn_table_name
    ip route add $remote_ip via $router_gateway dev wan table $vpn_table_name
    ip route add $wan_cidr dev $wan_interface_name table $vpn_table_name
done

ip route flush cache

down.sh

创建文件 /etc/openvpn/down.sh 并包含以下内容

#!/bin/sh

wanstrifconfig=$(ip -4 -o addr show wan)
wan_cidr=$(echo $wanstrifconfig | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\/[0-9]\{1,\}')

wan_interface_name=wan

vpn_gateway=$route_vpn_gateway
vpn_local=$ifconfig_local
vpn_mask=$ifconfig_netmask
remote_ip=$trusted_ip
device_name=$dev
router_gateway=$route_net_gateway

vpn_interface_cidr=`awk -v val="$vpn_gateway|$vpn_mask" '
function count1s(N){
    c = 0
    for(i=0; i<8; ++i) if(and(2**i, N)) ++c
    return c
}
function subnetmaskToPrefix(input) {
    split(input, inputParts, "|")
    split(inputParts[2], subnetParts, ".")
    split(inputParts[1], mainParts, ".")
  
  if (subnetParts[1] == 0 ) {
        mainParts[1] = 0
    }
    if (subnetParts[2] == 0 ) {
        mainParts[2] = 0
    }
    if (subnetParts[3] == 0 ) {
        mainParts[3] = 0
    }
    if (subnetParts[4] == 0 ) {
        mainParts[4] = 0
    }

     printf "%d.%d.%d.%d/%d", mainParts[1], mainParts[2], 
             mainParts[3], mainParts[4], count1s(subnetParts[1]) + count1s
}
BEGIN {
    subnetmaskToPrefix(val)
}'`

for vpn_table_name in custom_lan custom_wlan0 custom_wlan1 ; do
    ip route flush 0.0.0.0/1 via $vpn_gateway dev $device_name table $vpn_table_name
    ip route flush 128.0.0.0/1 via $vpn_gateway dev $device_name table $vpn_table_name
    ip route flush $vpn_interface_cidr dev $device_name scope link 
               src $vpn_local table $vpn_table_name
    ip route flush $remote_ip via $router_gateway dev wan table $vpn_table_name
    ip route flush $wan_cidr dev $wan_interface_name table $vpn_table_name
done

ip route flush cache

添加 LED 控制辅助脚本

隧道状态和脚本的连接状态可以在硬件 LED 上显示,这些 LED 通常在 OpenWRT 路由器上可用,以便无需访问终端即可快速了解隧道状态。以下辅助脚本由其他脚本使用,并应根据路由器型号上的 LED 进行修改。您可以在 此处 阅读有关 OpenWRT 路由器 LED 控制的信息。您可以使用以下命令查看路由器上可用的 LED

ls /sys/class/leds/

以下是 LED 控制脚本的文件夹结构和脚本内容。请在相同位置创建它们并设置为可执行。

auth-failed-led.sh

创建文件 /etc/openvpn/leds/auth-failed-led.sh 并包含以下内容

#!/bin/sh

status=$1
if [ "${status}" == "on" ]
then
    echo timer > /sys/class/leds/{your_custom_auth_failed_led}/trigger
fi
if [ "${status}" == "off" ]
then
    echo none > /sys/class/leds/{your_custom_auth_failed_led}/trigger
fi

connected-led.sh

创建文件 /etc/openvpn/leds/connected-led.sh 并包含以下内容

#!/bin/sh

status=$1
if [ "${status}" == "on" ]
then
    echo default-on > /sys/class/leds/{your_custom_connected_led}/trigger
fi
if [ "${status}" == "off" ]
then
    echo none > /sys/class/leds/{your_custom_connected_led}/trigger
fi

connecting-led.sh

创建文件 /etc/openvpn/leds/connecting-led.sh 并包含以下内容

#!/bin/sh

status=$1
if [ "${status}" == "on" ]
then
    echo timer > /sys/class/leds/{your_custom_connecting_led}/trigger
fi
if [ "${status}" == "off" ]
then
    echo none > /sys/class/leds/{your_custom_connecting_led}/trigger
fi

inactive-waiting-led.sh

创建文件 /etc/openvpn/leds/inactive-waiting-led.sh 并包含以下内容

#!/bin/sh

status=$1
if [ "${status}" == "on" ]
then
    echo timer > /sys/class/leds/{your_custom_inactive_led}/trigger
fi
if [ "${status}" == "off" ]
then
    echo none > /sys/class/leds/{your_custom_inactive_led}/trigger
fi

init-complete-led.sh

创建文件 /etc/openvpn/leds/init-complete-led.sh 并包含以下内容

#!/bin/sh

status=$1
if [ "${status}" == "on" ]
then
    echo default-on > /sys/class/leds/{your_custom_complete_led}/trigger
fi
if [ "${status}" == "off" ]
then
    echo none > /sys/class/leds/{your_custom_complete_led}/trigger
fi

步骤 3:VPN 提供商文件设置

configs 文件夹需要用 VPN 提供商的 *.ovpn 配置文件和包含认证详细信息的凭据文件进行填充,示例如下。

credentials

创建文件 /etc/openvpn/credentials 并包含以下内容

{your_vpn_username}
{your_vpn_password}

测试 VPN 提供商

您可以在终端中手动运行以下命令来测试您的 VPN 配置文件和凭据。

sh /etc/openvpn/resilient/start-openvpn-client.sh

在另一个终端中,您可以使用以下命令检查上述脚本的日志

cat /etc/tmp/openvpn-main-log

如果 VPN 提供商使用提供的 ovpn 配置文件和凭据正常工作,它将在日志中显示。

步骤 4:Ping 检查器脚本设置

如果您正在使用高可用性控制器脚本,它将根据 Ping 检查器脚本设置的状态来控制 VPN 连接。在此链接处阅读有关 pingcheck 的信息。Ping 检查脚本会调用控制器来控制 VPN 连接。

以下是 Ping 检查脚本的文件夹结构和脚本内容。请在相同位置创建它们并设置为可执行。

pingcheck-online.sh

创建文件 /etc/pingcheck/online.d/pingcheck-online.sh 并包含以下内容

#!/bin/sh

if [ "${INTERFACE}" == "wan" ]
then
    echo online > /tmp/pingcheck-wanstate
fi

if [ "${INTERFACE}" == "ovpn" ]
then
    echo online > /tmp/pingcheck-ovpnstate
fi

sh /etc/openvpn/resilient/resilient-vpn-pingcheck-controller.sh

pingcheck-offline.sh

创建文件 /etc/pingcheck/offline.d/pingcheck-offline.sh 并包含以下内容

#!/bin/sh

if [ "${INTERFACE}" == "wan" ]
then
    echo offline > /tmp/pingcheck-wanstate
fi

if [ "${INTERFACE}" == "ovpn" ]
then
    echo offline > /tmp/pingcheck-ovpnstate
fi

sh /etc/openvpn/resilient/resilient-vpn-pingcheck-controller.sh

pingcheck-panic.sh

创建文件 /etc/pingcheck/panic.d/pingcheck-panic.sh 并包含以下内容

#!/bin/sh

echo online > /tmp/pingcheck-panicstate
sh /etc/openvpn/resilient/resilient-vpn-pingcheck-controller.sh

最后一步:Ping 检查器配置

将以下内容添加到 /etc/config/pingcheck 的 Ping 检查器配置文件中

config default
        option host 208.67.222.222
        option interval 10
        option timeout 120
        option panic 4

config interface
        option name wan

config interface
        option name ovpn
        option host 208.67.222.222
        option interval 10
        option timeout 40

超时可以根据用户偏好进行修改,请记住 WAN 超时必须大于 VPN 超时。重启路由器并检查客户端的互联网访问和 VPN 连接。

(可选) - 备用高可用性控制器模式

对于互联网连接不稳定的用户,上述算法将在互联网中断超过 /etc/config/pingcheck 配置文件中描述的 timeout seconds 参数时进行重新连接,这对于几分钟的断网来说是不有效的重新连接。如果希望连接至少保持几分钟,希望在此期间互联网恢复,以下是备用的高可用性连接脚本。如果互联网通常稳定,则不建议使用此模式。

在此模式下更新 /etc/config/pingcheck 的 Ping 检查器配置文件中的以下内容。

config default
        option host 208.67.222.222
        option interval 10
        option timeout 30
        option panic 4

config interface
        option name wan

config interface
        option name ovpn
        option host 208.67.222.222
        option interval 10
        option timeout 50

请注意,在此模式下 WAN 超时低于 VPN 超时。粗体行已更改。请注意,panic 4 表示连接将保持四分钟。

resilient-vpn-pingcheck-controller.sh

/etc/openvpn/resilient/resilient-vpn-pingcheck-controller.sh 替换为以下内容以用于备用操作模式。

#!/bin/sh

wanstateret=`cat /tmp/pingcheck-wanstate`
ovpnstateret=`cat /tmp/pingcheck-ovpnstate`

wanonline=`echo "$wanstateret" online | awk '{ print ($1 == $2) ? 1 : 0 }'`
ovpnonline=`echo "$ovpnstateret" online | awk '{ print ($1 == $2) ? 1 : 0 }'`

resilientrunningret=`cat /tmp/resilientrunningstatus`
resilientrunningstatus=`echo "$resilientrunningret" running | 
                        awk '{ print ($1 == $2) ? 1 : 0 }'`

panicstateret=`cat /tmp/pingcheck-panicstate`
panicstate=`echo "$panicstateret" online | awk '{ print ($1 == $2) ? 1 : 0 }'`

wanoutfirstret=`cat /tmp/resilient-wanoutfirst`
wanoutfirststatus=`echo "$wanoutfirstret" yes | awk '{ print ($1 == $2) ? 1 : 0 }'`

if [ $wanonline -eq 1 ]
then
    if [ $ovpnonline -eq 0 ] && [ $wanoutfirststatus -eq 1 ]
    then
        rm /tmp/resilient-wanoutfirst
        (sh /etc/openvpn/resilient/check-vpn-connection.sh >/dev/null 2>&1 )&
    fi
    if [ $ovpnonline -eq 0 ] && [ $wanoutfirststatus -eq 0 ]
    then
        /etc/openvpn/leds/connected-led.sh off
        if [ $resilientrunningstatus -eq 0 ]
        then
            (sh /etc/openvpn/resilient/start-resilient-vpn.sh >/dev/null 2>&1 )&
            echo running > /tmp/resilientrunningstatus
        fi
        if [ $resilientrunningstatus -eq 1 ]
        then
            sh /etc/openvpn/resilient/kill-vpn.sh
        fi
    fi
    if [ $ovpnonline -eq 1 ] 
    then
        /etc/openvpn/leds/init-complete-led.sh off
        /etc/openvpn/leds/connected-led.sh on
    fi
fi

if [ $wanonline -eq 0 ]
then
    if [ $ovpnonline -eq 0 ] && [ $panicstate -eq 1 ]
    then
        sh /etc/openvpn/resilient/stop-resilient-vpn.sh
        echo stopped > /tmp/resilientrunningstatus
        rm /tmp/pingcheck-panicstate
    fi
    if [ $ovpnonline -eq 1 ] 
    then
        /etc/openvpn/leds/init-complete-led.sh on
        /etc/openvpn/leds/connected-led.sh on
        echo yes > /tmp/resilient-wanoutfirst
    fi
fi

诊断

如果出现问题,您可以检查以下步骤

  • 检查所有脚本的可执行状态
  • 检查日志文件:/tmp/openvpn-main-log
  • 删除热插拔脚本并测试互联网访问
  • 手动运行 start-openvpn-client.sh 并检查 /tmp/openvpn-main-log 的日志文件

结语

这将是我关于此主题的最后一篇文章,因为我认为我这边无法再进行改进,并且实现了高可用性随机紧急开关 VPN 路由器的目标。我希望我的努力能让寻求相同解决方案的人们更轻松。如果您需要任何澄清或设置方面的帮助,请联系我!

历史

  • 2023 年 7 月 16 日:初始版本
© . All rights reserved.