From e75a57b74fc3800f7d93b1c3c9e2c5fc4b3ff62c Mon Sep 17 00:00:00 2001 From: xihale Date: Sat, 13 Sep 2025 12:44:12 +0800 Subject: [PATCH 1/5] fix: ipv6 regex --- scripts/{ipv4.fish => ip.fish} | 108 +++++++++------------------------ scripts/ipv4.sh | 63 ------------------- 2 files changed, 27 insertions(+), 144 deletions(-) rename scripts/{ipv4.fish => ip.fish} (70%) delete mode 100644 scripts/ipv4.sh diff --git a/scripts/ipv4.fish b/scripts/ip.fish similarity index 70% rename from scripts/ipv4.fish rename to scripts/ip.fish index 30f5f8d..796b046 100755 --- a/scripts/ipv4.fish +++ b/scripts/ip.fish @@ -1,65 +1,54 @@ #!/usr/bin/env fish # Cloudflare Dynamic DNS Updater (IPv4 & IPv6) -# 自动更新 Cloudflare DNS 记录为当前 PPPoE 拨号的内网 IP 地址 +# 自动更新 Cloudflare DNS 记录为当前 default route 的 IP 地址 # 支持同时更新 IPv4 (A 记录) 和 IPv6 (AAAA 记录) # 如果不需要更新某种类型的记录,请将对应的域名设为空,ID 可以留空以启用自动检测 +source utils.fish + # Cloudflare Zone ID # DNS 配置主界面(https://dash.cloudflare.com//) > API -set -g ZONE_ID xxx +set ZONE_ID # Cloudflare API Token -set -g TOKEN xxx +set TOKEN # IPv4 配置 (如果不需要 IPv4 更新,请将这些变量设为空) # RECORD_ID 可以通过 API 获取 -set -g IPV4_DOMAIN "" -set -g IPV4_RECORD_ID "" +set IPV4_DOMAIN +# 留空以启用自动检测 +set IPV4_RECORD_ID # IPv6 配置 (如果不需要 IPv6 更新,请将这些变量设为空) -set -g IPV6_DOMAIN "" -set -g IPV6_RECORD_ID "" - -# PPPoE 接口名称(根据实际情况修改) -set -g PPPOE_INTERFACE pppoe-wan +set IPV6_DOMAIN +# 留空以启用自动检测 +set IPV6_RECORD_ID # DNS 记录配置 -set -g DNS_TTL 120 -set -g DNS_PROXIED false +set DNS_TTL 120 +set DNS_PROXIED false -# 全局正则表达式映射 -set -g regex_A '^([0-9]{1,3}\.){3}[0-9]{1,3}$' -set -g regex_AAAA '^([0-9A-Fa-f]{0,4}:){2,7}[0-9A-Fa-f]{0,4}$' - -# ============================================================================= -# 辅助函数 -# ============================================================================= - -function log_info - printf "\033[36m%s %s\033[0m\n" "[INFO]" (string join " " $argv) >&2 -end - -function log_error - printf "\033[31m%s %s\033[0m\n" "[ERROR]" (string join " " $argv) >&2 -end - -function log_success - printf "\033[32m%s %s\033[0m\n" "[SUCCESS]" (string join " " $argv) >&2 -end function validate_ip + + set -l regex_A '^([0-9]{1,3}\.){3}[0-9]{1,3}$' + set -l regex_AAAA '^([0-9A-Fa-f]{0,4}:){2,7}[0-9A-Fa-f]{0,4}$' + set -l type $argv[1] set -l ip $argv[2] set -l regex (eval echo \${regex_$type}) string match -q -r $regex $ip end -function get_pppoe_ip +function get_ip set -l type $argv[1] - set -l flag (string match -q A $type; and echo -4; or echo -6) - set -l filter (string match -q A $type; and echo inet; or echo inet6.*global) - set -l ip (ip $flag addr show $PPPOE_INTERFACE 2>/dev/null | awk "/$filter/ {print \$2}" | cut -d'/' -f1 | head -n 1) + switch $type + case A + set ip (ip -4 route | grep "default" | awk '{print $NF}') + case AAAA + set ip (ip -6 addr show scope global | grep inet6 | head -1 | awk '{print $2}' | cut -d'/' -f1) + end test -n "$ip"; or begin log_error "获取 $type 地址失败: $ip"; return 1; end validate_ip $type $ip; or begin log_error "$type 地址格式无效: $ip"; return 1; end echo $ip @@ -72,10 +61,9 @@ function get_dns_record log_info "获取 $type 记录..." curl -s -X GET $url -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" | read -l response; or begin log_error "请求失败"; return 1; end - string match -q '"success":true' $response; or begin log_error "Cloudflare API 错误: $response"; return 1; end + string match -q '*"success":true*' $response; or begin log_error "Cloudflare API 错误: $response"; return 1; end - set -l regex (eval echo \${regex_$type}) - set -l ip (string match -r -o $regex $response) + set -l ip (echo $response | sed -n 's/.*"content":"\([^" ]*\)".*/\1/p') test -n "$ip"; or begin log_error "未提取到 IP"; return 1; end validate_ip $type $ip; or begin log_error "IP 格式无效: $ip"; return 1; end @@ -149,38 +137,6 @@ function update_cloudflare_dns_record end end # update_cloudflare_dns_record 函数结束 -# ============================================================================= -# 自动检测并更新 Record ID -# ============================================================================= -function auto_detect_record_id - # 参数: record_type, domain, record_id_var_name - set -l record_type $argv[1] - set -l domain $argv[2] - set -l record_id_var_name $argv[3] - - if test -z "$domain" - # 未配置域名, nothing to do - return - # 尝试解析错误信息 - set -l error_msg (echo $response | sed -n 's/.*"message":"\([^"]*\)".*/\1/p') - if test -n "$error_msg" - log_error "错误信息: $error_msg" - end - - # 检查常见错误原因 - if string match -q "*authentication*" $response - log_error "认证失败,请检查 TOKEN 是否正确" - else if string match -q "*not found*" $response - log_error "DNS 记录未找到,请检查 Record ID 是否正确" - else if string match -q "*invalid*" $response - log_error "请求参数无效,请检查配置" - end - - log_error "完整响应内容: $response" - return 1 - end -end # update_cloudflare_dns_record 函数结束 - # ============================================================================= # 自动检测并更新 Record ID # ============================================================================= @@ -231,27 +187,17 @@ end log_info "开始检查 Cloudflare DNS 记录更新..." -# 自动检测并更新 Record ID -# auto_detect_record_id A IPV4_DOMAIN IPV4_RECORD_ID -# auto_detect_record_id AAAA IPV6_DOMAIN IPV6_RECORD_ID - -# 在主循环中按需自动检测 Record ID(也可单独调用) -# auto_detect_record_id A "$IPV4_DOMAIN" IPV4_RECORD_ID -# auto_detect_record_id AAAA "$IPV6_DOMAIN" IPV6_RECORD_ID - set -l record_var_names IPV4_RECORD_ID IPV6_RECORD_ID # 支持的记录类型数组 set -l types A AAAA set -l domains $IPV4_DOMAIN $IPV6_DOMAIN set -l record_ids $IPV4_RECORD_ID $IPV6_RECORD_ID -set -l pppoe_funcs get_pppoe_ipv4 get_pppoe_ipv6 for i in (seq (count $types)) set -l type $types[$i] set -l domain $domains[$i] set -l record_id $record_ids[$i] - set -l pppoe_func $pppoe_funcs[$i] set -l record_var_name $record_var_names[$i] if test -z "$domain" @@ -271,7 +217,7 @@ for i in (seq (count $types)) log_info "=== 处理 $type 记录 ($domain) ===" # 获取本地 IP - set -l local_ip ($pppoe_func) + set -l local_ip (get_ip $type) if test $status -ne 0 log_error "获取本地 $type 地址失败,跳过" continue diff --git a/scripts/ipv4.sh b/scripts/ipv4.sh deleted file mode 100644 index fe9a678..0000000 --- a/scripts/ipv4.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/sh - -# Cloudflare API 相关信息 -# Cloudflare API 端点,替换为实际的 API URL -CF_API="" -# Cloudflare API Token,换成你自己的 -CF_TOKEN="" -# Cloudflare 域名,换成你自己的,这个是你要访问的域名 -CF_DOMAIN="" - -# 获取 PPPoE 拨号的内网 IP 地址(假设接口名称为 pppoe-wan,根据实际情况修改) -INTERNAL_IP=$(ip -4 addr show pppoe-wan | awk '/inet/ {print $2}' | cut -d'/' -f1 | head -n 1) - -# 判断是否获取到 IP 地址 -if [ -z "$INTERNAL_IP" ]; then - echo "[$(date +'%Y-%m-%d %H:%M:%S')] [ERROR] 未能获取 PPPoE 内网 IP 地址" - exit 1 -fi - -echo "[$(date +'%Y-%m-%d %H:%M:%S')] [INFO] 当前 PPPoE 内网 IP 地址为:$INTERNAL_IP" - -# 获取 Cloudflare 上的现有 DNS 记录 IP 地址 -CURRENT_IP=$(curl -s -X GET "$CF_API" \ - -H "Authorization: Bearer $CF_TOKEN" \ - -H "Content-Type: application/json" | \ - sed -n 's/.*"content":"\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\)".*/\1/p') - -echo "[$(date +'%Y-%m-%d %H:%M:%S')] [INFO] Cloudflare 上的 IP 地址为:$CURRENT_IP" - -# 检查是否需要更新 -if [ "$INTERNAL_IP" = "$CURRENT_IP" ]; then - echo "[$(date +'%Y-%m-%d %H:%M:%S')] [INFO] Cloudflare 上的 IP 地址与当前 PPPoE 拨号的 IP 地址相同,无需更新。" - exit 0 -fi - -echo "[$(date +'%Y-%m-%d %H:%M:%S')] [INFO] Cloudflare 上的 IP 地址为:$CURRENT_IP,正在更新为:$INTERNAL_IP" - -# 构建 Cloudflare API 请求的 JSON 数据 -DATA=$(cat < Date: Sat, 13 Sep 2025 13:14:49 +0800 Subject: [PATCH 2/5] feat: smarter connet checking, reconnecting and login --- README.md | 30 ++++++++++++++------ scripts/.gitignore | 1 + scripts/generate_mac.sh | 16 +++++------ scripts/ip.fish | 20 +++++++------ scripts/kc.fish | 49 ++++++++++++++++++++++++++++++++ scripts/login.fish | 27 ++++++++++++++++++ scripts/ping.sh | 62 ----------------------------------------- scripts/utils_lib.fish | 11 ++++++++ 8 files changed, 129 insertions(+), 87 deletions(-) create mode 100644 scripts/.gitignore create mode 100755 scripts/kc.fish create mode 100644 scripts/login.fish delete mode 100644 scripts/ping.sh create mode 100644 scripts/utils_lib.fish diff --git a/README.md b/README.md index 4c3f306..9260fb3 100644 --- a/README.md +++ b/README.md @@ -24,12 +24,14 @@ generate_mac() { 平常使用直接 `./generate_mac.sh` 运行就行 -## ipv4.sh +## ip.sh 用来通过 Cloudflare 绑定的域名进行内网 DDNS 的脚本,目的是为了在大内网的其他地方也能够访问到内网的设备 需要自己调整 Cloudflare 的相关内容 +新版本同时支持 v6 & v4,只需要配置或留空对应的位置即可 + ```bash # Cloudflare API 相关信息 # Cloudflare API 端点,替换为实际的 API URL @@ -40,13 +42,7 @@ CF_TOKEN="" CF_DOMAIN="" ``` -平时使用直接 `./ipv4.sh` 运行就行 - -## ping.sh - -通过对网关进行 ping 操作来判断机身是否断开 pppoe 连接,需要与 `generate_mac.sh` 和 `ipv4.sh` 一起使用(DDNS 脚本不用的话注释掉就行) - -建议开机运行 +平时使用直接 `./ip.fish` 运行就行 ## swap.sh @@ -54,6 +50,24 @@ CF_DOMAIN="" 直接 `./swap.sh` 运行就行 +## kc.fish + +Keep Connection - 自动检测连接状态并在断线或者新设备加入触发设备踢出时重拨 + +使用方法: +```bash +./kc.fish +``` + +配置说明(在脚本开头可配置): +- `max_retry`: 最大重试次数(默认30次) +- `sleep_time`: 重拨后等待网络稳定时间(秒,默认10秒) +- `overhead_interval`: 正常状态检测间隔(秒,默认3秒) +- `max_fail`: 最大连续失败次数(触发重拨,默认3次) +- `ping_target`: 检测连接的目标地址(默认 https://baidu.com) + +脚本会持续运行,建议通过 `screen` 或 `tmux` 后台运行 + ## utils.sh Openwrt 备份脚本,注意自己调整备份文件保存的位置,建议使用 SMB 存储或者插个 U 盘 diff --git a/scripts/.gitignore b/scripts/.gitignore new file mode 100644 index 0000000..1761c01 --- /dev/null +++ b/scripts/.gitignore @@ -0,0 +1 @@ +.envrc \ No newline at end of file diff --git a/scripts/generate_mac.sh b/scripts/generate_mac.sh index 6259477..a273b15 100644 --- a/scripts/generate_mac.sh +++ b/scripts/generate_mac.sh @@ -2,13 +2,14 @@ # 生成一个随机的MAC地址 generate_mac() { - # 固定的前缀,格式为 aa:bb:cc - PREFIX="" - # 使用 /dev/urandom 获取随机数 - HEX1=$(hexdump -n 1 -e '1/1 "%02X"' /dev/urandom) - HEX2=$(hexdump -n 1 -e '1/1 "%02X"' /dev/urandom) - HEX3=$(hexdump -n 1 -e '1/1 "%02X"' /dev/urandom) - echo "$PREFIX:$HEX1:$HEX2:$HEX3" + # 固定的前缀,格式为 aa:bb:cc + # PREFIX="" + + # 使用 /dev/urandom 获取随机数 + HEX1=$(hexdump -n 1 -e '1/1 "%02X"' /dev/urandom) + HEX2=$(hexdump -n 1 -e '1/1 "%02X"' /dev/urandom) + HEX3=$(hexdump -n 1 -e '1/1 "%02X"' /dev/urandom) + echo "$PREFIX:$HEX1:$HEX2:$HEX3" } # 获取新的MAC地址 @@ -22,4 +23,3 @@ ip link set dev eth0 up # 验证修改是否成功 ip link show eth0 | grep ether - diff --git a/scripts/ip.fish b/scripts/ip.fish index 796b046..0756769 100755 --- a/scripts/ip.fish +++ b/scripts/ip.fish @@ -5,25 +5,25 @@ # 支持同时更新 IPv4 (A 记录) 和 IPv6 (AAAA 记录) # 如果不需要更新某种类型的记录,请将对应的域名设为空,ID 可以留空以启用自动检测 -source utils.fish +source utils_lib.fish # Cloudflare Zone ID # DNS 配置主界面(https://dash.cloudflare.com//) > API -set ZONE_ID +# set ZONE_ID # Cloudflare API Token -set TOKEN +# set TOKEN # IPv4 配置 (如果不需要 IPv4 更新,请将这些变量设为空) # RECORD_ID 可以通过 API 获取 -set IPV4_DOMAIN +# set IPV4_DOMAIN # 留空以启用自动检测 -set IPV4_RECORD_ID +# set IPV4_RECORD_ID # IPv6 配置 (如果不需要 IPv6 更新,请将这些变量设为空) -set IPV6_DOMAIN +# set IPV6_DOMAIN # 留空以启用自动检测 -set IPV6_RECORD_ID +# set IPV6_RECORD_ID # DNS 记录配置 set DNS_TTL 120 @@ -168,10 +168,12 @@ function auto_detect_record_id set -l id (echo $resp | awk -F'"id":' '{print $2}' | cut -d '"' -f2 | head -n 1) if test -n "$id" log_success "$record_type Record ID 获取成功: $id" + # 确保变量定义未被注释 + sed -i "s@^#\s*set $record_id_var_name@set $record_id_var_name@" (status --current-filename) # 更新运行时变量 - set -g $record_id_var_name $id + set $record_id_var_name $id # 自我更新脚本文件中对应行 - sed -i "s@set -g $record_id_var_name.*@set -g $record_id_var_name \"$id\"@" (status --current-filename) + sed -i "s@set $record_id_var_name.*@set $record_id_var_name \"$id\"@" (status --current-filename) # 返回 id 以便调用处捕获 echo $id return 0 diff --git a/scripts/kc.fish b/scripts/kc.fish new file mode 100755 index 0000000..231f791 --- /dev/null +++ b/scripts/kc.fish @@ -0,0 +1,49 @@ +#!/usr/bin/env fish + +# Keep Connection - 自动检测连接状态并在断线时重拨 + +source utils_lib.fish + +# 重试配置 +set max_retry 30 # 最多重试次数 + +# 设置重拨后休眠时间(秒) +set sleep_time 10 +set overhead_interval 3 +set max_fail 3 + +# TODO: 其实这里不需要 ping 只需要 访问一个 http 网站检测是否重定向就可以了 +set ping_target "https://baidu.com" + +function reconnect + echo "Network appears to be down... Reconnecting..." + /root/generate_mac.sh + while true + set gateway (ip route | grep "default via" | awk '{print $3}') + if test -n "$gateway" + log_success "Gateway detected: $gateway" + break + end + end + /root/login.fish + sleep 25 + /root/ip.fish + echo "Waiting for network to stabilize..." + sleep $sleep_time + echo "Attempting to get new gateway address after reconnection..." +end + +while true + set count 0 + while not curl -I --connect-timeout 1 $ping_target >/dev/null 2>&1 + set count (math "$count + 1") + if test $count -gt $max_fail + reconnect + break + end + log_info "Ping to target $ping_target failed. Failure count: $count. Retrying..." + end + log_success "Ping to target $ping_target successful." + + sleep $overhead_interval +end diff --git a/scripts/login.fish b/scripts/login.fish new file mode 100644 index 0000000..d9b3f37 --- /dev/null +++ b/scripts/login.fish @@ -0,0 +1,27 @@ +#!/usr/bin/env fish + +# 如果你采用 PPPOE 方案则不用设置账号和密码 +# set user_account "" +# set password "" + +# 获取 eth0 接口的 IPv4 地址 +set -l ip_address (ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1) + +# 检查是否成功获取到 IP 地址 +if test -z "$ip_address" + echo "错误: 无法获取 eth0 接口的 IP 地址" + exit 1 +end + +echo "获取到的 IP 地址: $ip_address" + +if test -n "$user_account"; and test -n "$password" + # 执行 curl 命令,将 IP 地址替换到相应位置 + curl "http://10.0.3.2:801/eportal/portal/login?callback=dr1004&login_method=1&user_account=%2C0%2C$user_account&user_password=$password&wlan_user_ip=$ip_address&wlan_user_ipv6=&wlan_ac_ip=172.16.254.2&wlan_ac_name=&jsVersion=4.1.3&terminal_type=1&lang=zh-cn&v=6985&lang=zh" \ + -H 'Accept: */*' \ + -H 'Accept-Language: zh-CN,zh;q=0.9' \ + -H 'Connection: keep-alive' \ + -H 'Referer: http://10.0.3.2/' \ + -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36' \ + --insecure +end diff --git a/scripts/ping.sh b/scripts/ping.sh deleted file mode 100644 index 7ed48d6..0000000 --- a/scripts/ping.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/sh - -# 获取 PPPoE 网关地址 -get_gateway() { - GATEWAY=$(ip route | grep "default via" | grep "pppoe" | awk '{print $3}') - if [ -z "$GATEWAY" ]; then - echo "Failed to get gateway address. Waiting for network to stabilize and retrying..." - # 如果获取网关失败,等待一段时间后重试 - sleep 5 - GATEWAY=$(ip route | grep "default via" | grep "pppoe" | awk '{print $3}') - if [ -z "$GATEWAY" ]; then - echo "Still unable to get gateway address. Exiting..." - exit 1 - fi - fi - echo "Gateway detected: $GATEWAY" -} - -# 初始化网关地址 -# get_gateway - -# 设置失败次数计数器 -FAIL_COUNT=0 -# 设置连续失败的检测次数(3次) -MAX_FAIL=3 -# 设置重拨后休眠时间(秒) -SLEEP_TIME=120 -# 设置每次 ping 之间的间隔时间(1秒) -PING_INTERVAL=1 - -while true; do - # 进行一次 ping 操作,仅发送一个数据包,超时设置为1秒 - if ping -c 1 -W 1 "$GATEWAY" > /dev/null 2>&1; then - # ping 成功,重置失败计数器 - FAIL_COUNT=0 - echo "Ping to gateway $GATEWAY successful." - else - # ping 失败,增加失败计数器 - FAIL_COUNT=$((FAIL_COUNT + 1)) - echo "Ping to gateway $GATEWAY failed. Failure count: $FAIL_COUNT" - fi - - # 检查是否达到连续失败的最大次数 - if [ "$FAIL_COUNT" -ge "$MAX_FAIL" ]; then - echo "Network appears to be down... Executing scripts to reconnect..." - # 执行生成 MAC 地址脚本和重拨脚本 - /root/generate_mac.sh - sleep 10 - /root/ipv4.sh - # 休眠指定时间以等待网络恢复 - echo "Waiting for network to stabilize..." - sleep "$SLEEP_TIME" - # 重置失败计数器 - FAIL_COUNT=0 - # 重新获取网关地址(每次重拨后必须更新网关地址) - echo "Attempting to get new gateway address after reconnection..." - get_gateway - fi - - # 每次 ping 之间休眠指定时间 - sleep "$PING_INTERVAL" -done \ No newline at end of file diff --git a/scripts/utils_lib.fish b/scripts/utils_lib.fish new file mode 100644 index 0000000..5f1af8e --- /dev/null +++ b/scripts/utils_lib.fish @@ -0,0 +1,11 @@ +function log_info + printf "\033[36m%s %s\033[0m\n" "[INFO]" (string join " " $argv) >&2 +end + +function log_error + printf "\033[31m%s %s\033[0m\n" "[ERROR]" (string join " " $argv) >&2 +end + +function log_success + printf "\033[32m%s %s\033[0m\n" "[SUCCESS]" (string join " " $argv) >&2 +end \ No newline at end of file From 2dfc742872fa03e6027e448928e989aeaea8453a Mon Sep 17 00:00:00 2001 From: xihale Date: Sat, 28 Feb 2026 16:45:15 +0800 Subject: [PATCH 3/5] Improve connection check logic and ignore local login helper --- scripts/.gitignore | 3 ++- scripts/kc.fish | 38 ++++++++++++++++---------------------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/scripts/.gitignore b/scripts/.gitignore index 1761c01..64dc0f0 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -1 +1,2 @@ -.envrc \ No newline at end of file +.envrc +l.fish \ No newline at end of file diff --git a/scripts/kc.fish b/scripts/kc.fish index 231f791..805776e 100755 --- a/scripts/kc.fish +++ b/scripts/kc.fish @@ -4,46 +4,40 @@ source utils_lib.fish -# 重试配置 -set max_retry 30 # 最多重试次数 - -# 设置重拨后休眠时间(秒) -set sleep_time 10 -set overhead_interval 3 -set max_fail 3 - -# TODO: 其实这里不需要 ping 只需要 访问一个 http 网站检测是否重定向就可以了 -set ping_target "https://baidu.com" +# 配置 +set overhead_interval 1 # 检测间隔 +set check_url "http://connect.rom.miui.com/generate_204" function reconnect echo "Network appears to be down... Reconnecting..." /root/generate_mac.sh + while true set gateway (ip route | grep "default via" | awk '{print $3}') if test -n "$gateway" log_success "Gateway detected: $gateway" break end + sleep 1 end + /root/login.fish - sleep 25 - /root/ip.fish + # sleep 25 + # /root/ip.fish + echo "Waiting for network to stabilize..." - sleep $sleep_time echo "Attempting to get new gateway address after reconnection..." end while true - set count 0 - while not curl -I --connect-timeout 1 $ping_target >/dev/null 2>&1 - set count (math "$count + 1") - if test $count -gt $max_fail - reconnect - break - end - log_info "Ping to target $ping_target failed. Failure count: $count. Retrying..." + set http_code (curl -I -s -o /dev/null -w "%{http_code}" $check_url 2>/dev/null) + + if test "$http_code" != 204 + log_info "Connection check failed (HTTP $http_code). Reconnecting..." + reconnect + else + log_success "Connection check to $check_url successful." end - log_success "Ping to target $ping_target successful." sleep $overhead_interval end From 77ce527d40a4ae86249120cd409716575256442e Mon Sep 17 00:00:00 2001 From: xihale Date: Thu, 19 Mar 2026 08:16:24 +0800 Subject: [PATCH 4/5] fix: use relative path --- scripts/kc.fish | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/kc.fish b/scripts/kc.fish index 805776e..c7208f1 100755 --- a/scripts/kc.fish +++ b/scripts/kc.fish @@ -10,7 +10,7 @@ set check_url "http://connect.rom.miui.com/generate_204" function reconnect echo "Network appears to be down... Reconnecting..." - /root/generate_mac.sh + ./generate_mac.sh while true set gateway (ip route | grep "default via" | awk '{print $3}') @@ -21,9 +21,9 @@ function reconnect sleep 1 end - /root/login.fish + ./login.fish # sleep 25 - # /root/ip.fish + # ./ip.fish echo "Waiting for network to stabilize..." echo "Attempting to get new gateway address after reconnection..." From 225161300c37229a4a54e28cf5d2d8a8672134dc Mon Sep 17 00:00:00 2001 From: xihale Date: Thu, 19 Mar 2026 08:52:04 +0800 Subject: [PATCH 5/5] refactor: use dynamic interface detection and add startup script - Add startup.sh script to automatically start kc session in tmux - Refactor all scripts to detect default network interface dynamically instead of hardcoding eth0 - Update generate_mac.sh, kc.fish, login.fish, mac.sh to use dynamic interface detection - Fix bracket syntax issues in utils.sh (change [[ to [) - Add get_default_iface function to utils_lib.fish --- scripts/generate_mac.sh | 30 ++++++++++++++++++++---------- scripts/kc.fish | 34 +++++++++++++++++++++------------- scripts/login.fish | 26 +++++++++++++++----------- scripts/mac.sh | 27 +++++++++++++++++++-------- scripts/startup.sh | 24 ++++++++++++++++++++++++ scripts/utils.sh | 8 ++++---- scripts/utils_lib.fish | 10 ++++++++++ 7 files changed, 113 insertions(+), 46 deletions(-) create mode 100644 scripts/startup.sh diff --git a/scripts/generate_mac.sh b/scripts/generate_mac.sh index a273b15..5f26de9 100644 --- a/scripts/generate_mac.sh +++ b/scripts/generate_mac.sh @@ -1,25 +1,35 @@ #!/bin/sh +# 获取默认接口 +get_default_iface() { + iface=$(ip route | grep "default" | awk '{print $5}' | head -n 1) + if [ -z "$iface" ]; then + iface=$(ip link show up | grep -v "lo" | head -n 1 | awk -F': ' '{print $2}') + fi + echo "$iface" +} + +IFACE=$(get_default_iface) + # 生成一个随机的MAC地址 generate_mac() { - # 固定的前缀,格式为 aa:bb:cc - # PREFIX="" - # 使用 /dev/urandom 获取随机数 HEX1=$(hexdump -n 1 -e '1/1 "%02X"' /dev/urandom) HEX2=$(hexdump -n 1 -e '1/1 "%02X"' /dev/urandom) HEX3=$(hexdump -n 1 -e '1/1 "%02X"' /dev/urandom) - echo "$PREFIX:$HEX1:$HEX2:$HEX3" + # 保持前缀 (可以使用固定前缀,这里演示随机) + echo "00:E0:4C:$HEX1:$HEX2:$HEX3" } # 获取新的MAC地址 NEW_MAC=$(generate_mac) -echo "生成的新MAC地址为: $NEW_MAC" +echo "针对接口 $IFACE 生成的新MAC地址为: $NEW_MAC" -# 使用新的MAC地址修改eth0的MAC地址 -ip link set dev eth0 down -ip link set dev eth0 address $NEW_MAC -ip link set dev eth0 up +# 使用新的MAC地址修改网卡的MAC地址 +ip link set dev "$IFACE" down +ip link set dev "$IFACE" address "$NEW_MAC" +ip link set dev "$IFACE" up # 验证修改是否成功 -ip link show eth0 | grep ether +echo "验证修改结果:" +ip link show "$IFACE" | grep ether diff --git a/scripts/kc.fish b/scripts/kc.fish index c7208f1..5c3d305 100755 --- a/scripts/kc.fish +++ b/scripts/kc.fish @@ -9,8 +9,8 @@ set overhead_interval 1 # 检测间隔 set check_url "http://connect.rom.miui.com/generate_204" function reconnect - echo "Network appears to be down... Reconnecting..." - ./generate_mac.sh + log_info "Network appears to be down... Reconnecting..." + sh generate_mac.sh while true set gateway (ip route | grep "default via" | awk '{print $3}') @@ -21,23 +21,31 @@ function reconnect sleep 1 end - ./login.fish - # sleep 25 - # ./ip.fish + fish login.fish + sleep 3 + # fish ip.fish - echo "Waiting for network to stabilize..." - echo "Attempting to get new gateway address after reconnection..." + log_info "Waiting for network to stabilize..." + log_info "Attempting to get new gateway address after reconnection..." end while true set http_code (curl -I -s -o /dev/null -w "%{http_code}" $check_url 2>/dev/null) - if test "$http_code" != 204 - log_info "Connection check failed (HTTP $http_code). Reconnecting..." - reconnect - else + if test "$http_code" = 204 log_success "Connection check to $check_url successful." - end + sleep $overhead_interval + else + if test "$http_code" = 302 + log_info "Detected captive portal (HTTP 302). Attempting to login..." + else + log_info "Connection check failed (HTTP $http_code). Reconnecting..." + end + + reconnect - sleep $overhead_interval + # 登录/重连后多等一会儿,确保网关状态同步 + log_info "Post-reconnect cooldown..." + sleep 5 + end end diff --git a/scripts/login.fish b/scripts/login.fish index d9b3f37..ff755e2 100644 --- a/scripts/login.fish +++ b/scripts/login.fish @@ -1,27 +1,31 @@ #!/usr/bin/env fish +source utils_lib.fish + # 如果你采用 PPPOE 方案则不用设置账号和密码 # set user_account "" # set password "" -# 获取 eth0 接口的 IPv4 地址 -set -l ip_address (ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1) +# 动态获取默认接口 +set -l iface (get_default_iface) +# 使用 awk 替代 grep -oP 提取 IP +set -l ip_address (ip -4 addr show $iface | grep "inet " | awk '{print $2}' | cut -d/ -f1 | head -n 1) # 检查是否成功获取到 IP 地址 if test -z "$ip_address" - echo "错误: 无法获取 eth0 接口的 IP 地址" + log_error "无法获取接口 $iface 的 IP 地址" exit 1 end -echo "获取到的 IP 地址: $ip_address" +log_info "获取到的 IP 地址 ($iface): $ip_address" if test -n "$user_account"; and test -n "$password" - # 执行 curl 命令,将 IP 地址替换到相应位置 + echo 正在尝试登录... curl "http://10.0.3.2:801/eportal/portal/login?callback=dr1004&login_method=1&user_account=%2C0%2C$user_account&user_password=$password&wlan_user_ip=$ip_address&wlan_user_ipv6=&wlan_ac_ip=172.16.254.2&wlan_ac_name=&jsVersion=4.1.3&terminal_type=1&lang=zh-cn&v=6985&lang=zh" \ - -H 'Accept: */*' \ - -H 'Accept-Language: zh-CN,zh;q=0.9' \ - -H 'Connection: keep-alive' \ - -H 'Referer: http://10.0.3.2/' \ - -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36' \ - --insecure + -H 'Accept: */*' \ + -H 'Accept-Language: zh-CN,zh;q=0.9' \ + -H 'Connection: keep-alive' \ + -H 'Referer: http://10.0.3.2/' \ + -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36' \ + --insecure end diff --git a/scripts/mac.sh b/scripts/mac.sh index fac4d7a..24a9829 100644 --- a/scripts/mac.sh +++ b/scripts/mac.sh @@ -1,11 +1,22 @@ #!/bin/sh -MAC_FILE="/root/mac" +MAC_FILE="./mac" + +# 获取默认接口 +get_default_iface() { + iface=$(ip route | grep "default" | awk '{print $5}' | head -n 1) + if [ -z "$iface" ]; then + iface=$(ip link show up | grep -v "lo" | head -n 1 | awk -F': ' '{print $2}') + fi + echo "$iface" +} + +IFACE=$(get_default_iface) # 获取当前MAC地址并保存到文件 save_mac() { - CURRENT_MAC=$(ip link show eth0 | grep ether | awk '{print $2}') - echo "当前的MAC地址是: $CURRENT_MAC" + CURRENT_MAC=$(ip link show "$IFACE" | grep ether | awk '{print $2}') + echo "当前的MAC地址 ($IFACE) 是: $CURRENT_MAC" echo "$CURRENT_MAC" > "$MAC_FILE" echo "已保存当前MAC地址到 $MAC_FILE" } @@ -15,12 +26,12 @@ restore_mac() { if [ -f "$MAC_FILE" ]; then SAVED_MAC=$(cat "$MAC_FILE") echo "从文件恢复MAC地址: $SAVED_MAC" - ip link set dev eth0 down - ip link set dev eth0 address "$SAVED_MAC" - ip link set dev eth0 up - echo "已恢复MAC地址到eth0" + ip link set dev "$IFACE" down + ip link set dev "$IFACE" address "$SAVED_MAC" + ip link set dev "$IFACE" up + echo "已恢复MAC地址到 $IFACE" else - echo "MAC文件不存在,无法恢复MAC地址" + echo "MAC文件不存在: $MAC_FILE,无法恢复" fi } diff --git a/scripts/startup.sh b/scripts/startup.sh new file mode 100644 index 0000000..e7bd218 --- /dev/null +++ b/scripts/startup.sh @@ -0,0 +1,24 @@ +# 创建会话 +tmux new-session -d -s "kc" + +# 获取 tmux 默认使用的 shell +TMUX_SHELL=$(tmux show-options -gv default-shell 2>/dev/null) +if [ -z "$TMUX_SHELL" ]; then + TMUX_SHELL="$SHELL" +fi + +# 根据 shell 类型决定 source 命令 +case "$TMUX_SHELL" in + *fish) + SOURCE_CMD="source .envrc" + ;; + *) + # ash/bash/sh 环境下使用 . 且必须带路径以兼容所有环境 + SOURCE_CMD=". ./.envrc" + ;; +esac + +# 发送指令 +tmux send-keys -t "kc" "$SOURCE_CMD" Enter "./kc.fish" Enter + +exit 0 diff --git a/scripts/utils.sh b/scripts/utils.sh index f49a188..7fe09c2 100644 --- a/scripts/utils.sh +++ b/scripts/utils.sh @@ -72,7 +72,7 @@ restore_full_image() { # 确认操作 read -p "确定要恢复系统镜像吗?此操作不可逆![y/N]: " confirm - [[ "$confirm" != "y" && "$confirm" != "Y" ]] && return + [ "$confirm" != "y" ] && [ "$confirm" != "Y" ] && return # 解压并恢复 echo -e "${BLUE}[$(get_timestamp)] 正在解压镜像文件...${RESET}" @@ -112,7 +112,7 @@ restore_config() { # 确认操作 read -p "确定要恢复系统配置吗?[y/N]: " confirm - [[ "$confirm" != "y" && "$confirm" != "Y" ]] && return + [ "$confirm" != "y" ] && [ "$confirm" != "Y" ] && return # 创建临时备份 local current_backup="$OPENWRT_CONFIG_BACKUP_DIR/current_config_$(date +%H%M%S).bak" @@ -151,7 +151,7 @@ restore_iptables() { # 确认操作 read -p "确定要恢复iptables规则吗?[y/N]: " confirm - [[ "$confirm" != "y" && "$confirm" != "Y" ]] && return + [ "$confirm" != "y" ] && [ "$confirm" != "Y" ] && return if iptables-restore < $full_path; then echo -e "${GREEN}[$(get_timestamp)] iptables规则恢复成功!${RESET}" @@ -184,7 +184,7 @@ restore_firewall() { # 确认操作 read -p "确定要恢复防火墙配置吗?[y/N]: " confirm - [[ "$confirm" != "y" && "$confirm" != "Y" ]] && return + [ "$confirm" != "y" ] && [ "$confirm" != "Y" ] && return # 备份当前配置 local current_backup="$FIREWALL_BACKUP_DIR/current_firewall_$(date +%H%M%S).bak" diff --git a/scripts/utils_lib.fish b/scripts/utils_lib.fish index 5f1af8e..c6148e5 100644 --- a/scripts/utils_lib.fish +++ b/scripts/utils_lib.fish @@ -8,4 +8,14 @@ end function log_success printf "\033[32m%s %s\033[0m\n" "[SUCCESS]" (string join " " $argv) >&2 +end + +function get_default_iface + # 获取默认路由对应的网卡 + set -l iface (ip route | grep "default" | awk '{print $5}' | head -n 1) + if test -z "$iface" + # 回退到第一个非回环网卡 + set iface (ip link show up | grep -v "lo" | head -n 1 | awk -F': ' '{print $2}') + end + echo $iface end \ No newline at end of file