关联文章:
<QNAP 453D QTS-5.x> 日志记录:使用脚本 routeswitch.sh (旧名 script: router_switcher.sh) 在 NAS 里切换默认路由 -优快云博客
更新内容:
新增命令行参数,快捷工作模式。
如上图提示:显示菜单,显示所有路由,切换路由,恢复默认路由。
图形界面:
保留原界面
主要功能:
- 切换路由
- 切换路由判断
- 切换路由后会重新建立 Argo Tunnel 连接
- 如果切换路由失败,回退到系统默认路由
- 支持参数操作
脚本 routeswitcher-N.sh 内容:
#!/bin/sh
# Created by Dave on 20Jan.2025
# History of Version
# Ver.1.0 was re-created script to support UI with simple input.
# Ver.1.1 added get_vpn_location() for location list and public IP info
# Ver.1.2 added UTF-8 to support unicode
# Ver.1.3 added timeout and error handling for connection issues
# Ver.1.5 added default gateway variable
# Ver.1.6 added CURRENT_DEFAULT_ROUTE variable and show in status
# Ver.1.7 added VPN_INTERFACES veriable for matching fixed interfaces
# ver.1.8 added after switched route to update ROUTE_DEVICE in cron_default_route_changed.sh on 1Feb.2025
# Ver.1.9 added restart_cloudflared() for restarting Cloudflared, modified restore_default() and switch_to_vpn() to include Cloudflared restart on 1Feb.2025
# Version.2.0 modified switch VPN route logical on 2Feb.2025
# Version.2.1 added CLI parameters support for show and direct interface switching 7Feb.2025
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
# Define lines UI
TOP_LINE="━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
DIV_LINE="─────────────────────────────────────────────"
# Configuration variables
DEFAULT_GATEWAY="192.168.1.254"
DEFAULT_INTERFACE="br0"
LAST_IP=""
CURL_TIMEOUT=6
CURRENT_DEFAULT_ROUTE=$(ip route show default | awk '/^default/ {print $3; exit}')
VPN_INTERFACES="\(wgc3\|tun2\)"
# show usage
show_usage() {
echo "Usage:"
echo " $0 help - Show this usage"
echo " $0 show - Show current status and available routes"
echo " $0 <interface> - Swap route to use the specified VPN interface (e.g. wgc3001)"
echo " $0 default - Use default route"
}
# Get public IP with curl options for timeout
get_public_ip() {
ip=$(curl -s --connect-timeout 5 --max-time $CURL_TIMEOUT ifconfig.me)
if [ $? -eq 0 ] && [ -n "$ip" ]; then
echo "$ip"
return 0
else
echo "Unable to retrieve"
return 1
fi
}
# Update the current default route
update_default_route() {
CURRENT_DEFAULT_ROUTE=$(ip route show default | awk '/^default/ {print $3; exit}')
}
# Check if interface exists
check_interface() {
interface=$1
if ! ip link show dev "$interface" >/dev/null 2>&1; then
echo "Interface $interface does not exist"
return 1
fi
return 0
}
# Show current status
show_current_status() {
echo "$TOP_LINE"
echo " Default Route:"
ip route show default | sed 's/^/ /'
echo "$DIV_LINE"
echo " Public IP:"
CURRENT_IP=$(get_public_ip)
echo " Current: $CURRENT_IP"
echo " Current default route is: $CURRENT_DEFAULT_ROUTE"
if [ -n "$LAST_IP" ] && [ "$LAST_IP" != "$CURRENT_IP" ] && [ "$LAST_IP" != "Unable to retrieve" ]; then
echo " Previous: $LAST_IP"
fi
echo "$DIV_LINE"
}
# Update last IP before changing route
update_last_ip() {
LAST_IP=$(get_public_ip)
}
# Restart Cloudflared and check the exit code
restart_cloudflared() {
echo "Restarting Cloudflared..."
if /opt/CloudFlared/CloudFlared.sh restart; then
echo "Cloudflared restarted successfully"
sleep 1
else
echo "Error: Failed to restart Cloudflared"
sleep 1
# Retry restarting Cloudflared
for i in {1..3}; do
echo "Attempt $i to kill and restart Cloudflared..."
pkill -f cloudflared # Kill all cloudflared processes
sleep 1 # Wait a bit before restarting
if /opt/CloudFlared/CloudFlared.sh restart; then
echo "Cloudflared restarted successfully on attempt $i"
break
else
echo "Error: Failed to restart Cloudflared on attempt $i"
fi
done
# return error if failed after 3 attempts
if [ $i -eq 3 ]; then
echo "Error: Failed to restart Cloudflared after 3 attempts"
return 1
fi
fi
}
# Switch to specified VPN interface
switch_to_vpn() {
interface=$1
echo "Switching to VPN route using interface $interface..."
if ! check_interface "$interface"; then
return 1
fi
# Checking network connectivity
echo "Checking network connectivity..."
if ! get_public_ip >/dev/null; then
echo "Warning: Cannot get public IP. Network might be unstable."
echo "Attempting to restore default route first..."
# Restore default route
ip route del default 2>/dev/null || true
ip route add default via $DEFAULT_GATEWAY dev $DEFAULT_INTERFACE
sleep 2
# Verify default route connectivity
if ! get_public_ip >/dev/null; then
echo "Error: Cannot restore network connectivity with default route"
return 1
fi
echo "Successfully restored default route connectivity"
fi
update_last_ip
ip route del default 2>/dev/null || true
if ip route add default dev "$interface"; then
update_default_route
echo "Successfully switched to VPN route"
# Verify new route connectivity
echo "Verifying new route connectivity..."
sleep 2
if ! get_public_ip >/dev/null; then
echo "Error: Cannot verify connection after route change"
echo "Rolling back to default route..."
# Restore default route
ip route del default 2>/dev/null
ip route add default via $DEFAULT_GATEWAY dev $DEFAULT_INTERFACE
echo "Rolled back to default route"
sleep 2
return 1
fi
echo "Connection verified successfully"
sleep 1
# Update ROUTE_DEVICE in cron_default_route_changed.sh
sed -i "s/^ROUTE_DEVICE=.*/ROUTE_DEVICE=\"$interface\"/" /share/Multimedia/2024-MyProgramFiles/29.QTS_conf_files/cron/cron_default_route_changed.sh
echo "Updated ROUTE_DEVICE in cron_default_route_changed.sh to $interface"
sleep 1
# Restart Cloudflared
restart_cloudflared
return 0
else
echo "Error: Failed to add VPN route"
restore_default
sleep 1
return 1
fi
}
# Restore default route
restore_default() {
echo "Restoring default route..."
echo "Checking network connectivity..."
if ! get_public_ip >/dev/null; then
echo "Error: Cannot get public IP. Network might be unstable."
echo "Aborting route restoration..."
return 1
fi
update_last_ip
ip route del default 2>/dev/null || true
if ip route add default via $DEFAULT_GATEWAY dev $DEFAULT_INTERFACE; then
update_default_route
echo "Successfully restored default route"
echo "Verifying new route connectivity..."
sleep 2
if ! get_public_ip >/dev/null; then
echo "Error: Cannot verify connection after route change"
echo "Please check your network configuration manually"
return 1
fi
echo "Connection verified successfully"
sleep 1
# Update ROUTE_DEVICE in cron_default_route_changed.sh
sed -i "s/^ROUTE_DEVICE=.*/ROUTE_DEVICE=\"$DEFAULT_INTERFACE\"/" /share/Multimedia/2024-MyProgramFiles/29.QTS_conf_files/cron/cron_default_route_changed.sh
echo "Updated ROUTE_DEVICE in cron_default_route_changed.sh to $DEFAULT_INTERFACE"
sleep 1
# Restart Cloudflared
restart_cloudflared
return 0
else
echo "Error: Failed to restore default route"
sleep 1
return 1
fi
}
# Get location for VPN interfaces
get_vpn_location() {
case "$1" in
"wgc3001") echo "JPN";;
"wgc3002") echo "US.Texas1";;
"wgc3003") echo "US.Washington";;
"tun2001") echo "JP.Tokyo";;
"tun2002") echo "US.WestCoast";;
*) echo "Unknown";;
esac
}
# Show current status and available routes
show_status_and_routes() {
echo " VPN Route Switcher "
show_current_status
echo " Available Routes:"
echo " - DEFAULT ROUTE (192.168.1.254)"
ip link show | grep ": $VPN_INTERFACES" | cut -d: -f2 | tr -d ' ' | while read -r interface; do
location=$(get_vpn_location "$interface")
printf " - %-10s [%s]\n" "$interface" "$location"
done
echo "$TOP_LINE"
}
# Interactive menu function
show_interactive_menu() {
while true; do
clear
echo " VPN Route Switcher "
show_current_status
echo " Available Options:"
echo " 0) RESTORE DEFAULT ROUTE (192.168.1.254)"
ip link show | grep ": $VPN_INTERFACES" | cut -d: -f2 | tr -d ' ' > /tmp/vpn_interfaces.tmp
i=1
while read -r interface; do
location=$(get_vpn_location "$interface")
printf " %d) %-10s [%s]\n" "$i" "$interface" "$location"
i=$((i + 1))
done < /tmp/vpn_interfaces.tmp
echo "$DIV_LINE"
echo " Enter number to select (99/q/Q to exit)"
echo " Enter key to refresh"
echo "$TOP_LINE"
printf " Select → "
read choice
if [ "$choice" = "99" ] || [ "$choice" = "q" ] || [ "$choice" = "Q" ]; then
echo " Exiting..."
rm -f /tmp/vpn_interfaces.tmp
exit 0
fi
case $choice in
''|*[!0-9]*)
continue
;;
*)
if [ "$choice" -gt 99 ]; then
echo " Please enter a number between 0 and 99"
sleep 2
continue
fi
;;
esac
if [ "$choice" = "0" ]; then
if ! restore_default; then
echo "Press any key to continue..."
read -n 1
fi
else
selected_interface=$(sed -n "${choice}p" /tmp/vpn_interfaces.tmp)
if [ -n "$selected_interface" ]; then
location=$(get_vpn_location "$selected_interface")
echo "Switching to $selected_interface [$location]"
if ! switch_to_vpn "$selected_interface"; then
echo "Press any key to continue..."
read -n 1
fi
else
echo " Invalid selection: no interface for number $choice"
sleep 2
continue
fi
fi
rm -f /tmp/vpn_interfaces.tmp
done
}
# Main program
case "$1" in
"show")
show_status_and_routes
exit 0
;;
"help"|"-h"|"--help")
show_usage
exit 0
;;
"default")
echo "Restoring default route..."
restore_default
exit $?
;;
"")
# Go to interactive UI
show_interactive_menu
;;
*)
# Verify valid interface name
if echo "$1" | grep -q "^$VPN_INTERFACES"; then
if ip link show dev "$1" >/dev/null 2>&1; then
echo "Switching to interface $1..."
switch_to_vpn "$1"
exit $?
else
echo "Error: Interface $1 does not exist"
exit 1
fi
else
echo "Error: Invalid interface name"
show_usage
exit 1
fi
;;
esac
提示:
使用前加执行权限:
chmod +x routeswitcher-N.sh
VS Code 工具,推荐安装扩展 Amazon Q。
写完代码后,按 #+table 键,直接能生成注释。
写代码时,也会给出提示。以后按 table 键自己写代码更近一步。