<QNAP 453D QTS-5.x> 日志记录:脚本 routeswitch-N.sh 可在 NAS 中切换路由,更新 Argo Tunnel,获取出口 IP,工作方式:界面、参数

关联文章:

<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 键自己写代码更近一步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值