#!/bin/bash # ========================================================== # 脚本名称: tg_report.sh (Telegram 每日战报模块 - 动态锚点版) # 核心功能: 适配 Feature Flag 架构,按需展示独立统计数据,OTA 更新预警 # ========================================================== INSTALL_DIR="/opt/ip_sentinel" CONFIG_FILE="${INSTALL_DIR}/config.conf" LOG_FILE="${INSTALL_DIR}/logs/sentinel.log" # 1. 加载配置并自检 if [ ! -f "$CONFIG_FILE" ]; then exit 1; fi source "$CONFIG_FILE" if [ -z "$TG_TOKEN" ] || [ -z "$CHAT_ID" ]; then echo "⚠️ 未配置 Telegram 机器人参数,取消播报。" exit 0 fi # 2. 节点元数据抓取 (v3.2.2 协议自适应与多级容灾版) # [v3.5.2 核心: 引入双轨身份架构] if [ -z "$NODE_NAME" ]; then IP_HASH=$(echo "${PUBLIC_IP:-127.0.0.1}" | md5sum | cut -c 1-4 | tr 'a-z' 'A-Z') NODE_NAME="$(hostname | cut -c 1-10)-${IP_HASH}" fi NODE_ALIAS="${NODE_ALIAS:-$NODE_NAME}" # --- [防线 1: 底层路由锁定与协议自适应] --- CURL_BIND_OPT="" DYNAMIC_IP_PREF="-${IP_PREF:-4}" if [[ -n "$BIND_IP" && "$BIND_IP" =~ ^[0-9a-fA-F:\.]+$ ]]; then CURL_BIND_OPT="--interface $BIND_IP" if [[ "$BIND_IP" == *":"* ]]; then DYNAMIC_IP_PREF="-6" elif [[ "$BIND_IP" == *"."* ]]; then DYNAMIC_IP_PREF="-4" fi fi # 多节点容灾探测出口 IP (注入协议自适应) CURRENT_IP=$( (curl $CURL_BIND_OPT $DYNAMIC_IP_PREF -s -m 5 api.ip.sb/ip || curl $CURL_BIND_OPT $DYNAMIC_IP_PREF -s -m 5 ifconfig.me) 2>/dev/null | tr -d '[:space:]' ) # [v3.3.1 修改] 强制兜底:如果外部 API 挂了,优先使用固化的对外公网面孔 (兼容 NAT 机的空 BIND_IP) [ -z "$CURRENT_IP" ] && CURRENT_IP="${PUBLIC_IP:-$BIND_IP}" # 为可能获取到的 IPv6 自动添加方括号护甲 [[ "$CURRENT_IP" == *":"* ]] && [[ "$CURRENT_IP" != *"["* ]] && CURRENT_IP="[${CURRENT_IP}]" # --- [防线 2: 多级 ISP 容灾探针链路] --- ISP_INFO="" # 探针 A: 纯文本 API (免 jq,极速稳定) ISP_INFO=$(curl $CURL_BIND_OPT $DYNAMIC_IP_PREF -s -m 5 ipinfo.io/org 2>/dev/null) # 探针 B: 备用纯文本 API if [ -z "$ISP_INFO" ] || [[ "$ISP_INFO" == *"error"* ]]; then ISP_INFO=$(curl $CURL_BIND_OPT $DYNAMIC_IP_PREF -s -m 5 ip-api.com/line/?fields=isp 2>/dev/null) fi # 探针 C: 原版的 JSON API (需要 jq 兜底) if [ -z "$ISP_INFO" ] || [[ "$ISP_INFO" == *"error"* ]]; then if command -v jq &> /dev/null; then ISP_INFO=$(curl $CURL_BIND_OPT $DYNAMIC_IP_PREF -s -m 5 api.ip.sb/geoip | jq -r '.organization' 2>/dev/null) fi fi # --- [防线 3: 数据清洗 (遵循底层共识原则)] --- # 剔除 ipinfo 返回的开头 AS 号 (例如 "AS137535 JT TELECOM" -> "JT TELECOM") ISP_INFO=$(echo "$ISP_INFO" | sed -E 's/^AS[0-9]+ //') # 最终兜底判断 [ -z "$ISP_INFO" ] || [ "$ISP_INFO" == "null" ] && ISP_INFO="未知 ISP" if [[ "$ISP_INFO" == *"Cloudflare"* ]]; then IP_TYPE="Cloudflare Warp 🛰️" else IP_TYPE="$ISP_INFO 🏠" fi # 动态国旗 case "$REGION_CODE" in "JP") FLAG="🇯🇵" ;; "US") FLAG="🇺🇸" ;; "DE") FLAG="🇩🇪" ;; "SG") FLAG="🇸🇬" ;; "HK") FLAG="🇭🇰" ;; "GB"|"UK") FLAG="🇬🇧" ;; "AU") FLAG="🇦🇺" ;; *) FLAG="🌐" ;; esac # 3. 截取过去 24 小时的日志 (每天48次轮询,保留最新 1000 行足以覆盖单日战报) LOG_CONTENT=$(tail -n 1000 "$LOG_FILE" 2>/dev/null) if [ -z "$LOG_CONTENT" ]; then read -r -d '' MSG <> "${INSTALL_DIR}/logs/error.log" else echo "✅ 战报推送成功!" fi