diff --git a/README.md b/README.md index 972157e..2b35ffc 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,6 +42,9 @@ CF_TOKEN="" CF_DOMAIN="" ``` +<<<<<<< HEAD +平时使用直接 `./ip.fish` 运行就行 +======= `zone_id` 是你的 Cloudflare 的区域 ID,在域名的概览下就有 ![](https://bili33.eu.org/file/VkGuUz9S.png) @@ -75,6 +80,7 @@ EOF 通过对网关进行 ping 操作来判断机身是否断开 pppoe 连接,需要与 `generate_mac.sh` 和 `ipv4.sh` 一起使用(DDNS 脚本不用的话注释掉就行) 建议开机运行 +>>>>>>> upstream/fish ## swap.sh @@ -82,6 +88,24 @@ EOF 直接 `./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/ipv4.fish b/scripts/ip.fish similarity index 68% rename from scripts/ipv4.fish rename to scripts/ip.fish index 30f5f8d..0756769 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_lib.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 # ============================================================================= @@ -212,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 @@ -231,27 +189,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 +219,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 3b6eae8..0000000 --- a/scripts/ipv4.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/sh - -# Cloudflare API 相关信息 -# Cloudflare API 端点,替换为实际的 API URL -CF_API="https://api.cloudflare.com/client/v4/zones/{{zone_id}}/dns_records/{{record_id}}" -# Cloudflare API Token,换成你自己的 -CF_TOKEN="" -# Cloudflare 域名,换成你自己的,这个是你要访问的域名 -CF_DOMAIN="" - -# 获取 PPPoE 拨号的内网 IP 地址 -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 </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