侧边栏壁纸
  • 累计撰写 57 篇文章
  • 累计创建 74 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

Moecloud 台湾家宽Hinet应对GWF防火墙墙端口自动更换IP

Seger
2025-09-09 / 0 评论 / 0 点赞 / 7 阅读 / 2,528 字

在内地机和台湾机安装依赖

1.在脚本所在 VPS安装依赖:

apt-get update && apt-get install -y sshpass netcat-openbsd

2.探测节点(内地机)若缺 nc:

apt-get update && apt-get install -y netcat-openbsd

创建运行脚本

nano ip_probe.sh

复制下面内容到脚本内

#!/usr/bin/env bash
set -euo pipefail

### =========== 配置区 ===========
PORTS=(59141 44299)

CN_HOST="你的内地主机IP"
CN_USER="主机用户名"
CN_PASS="你的root密码"
CN_PORT=22 #主机ssh端口

ATTEMPTS=30
SLEEP_BETWEEN=1

CHANGE_IP_URL="http://100.100.101.101:8002/changeip" #moecloud 更换ip的地址

WAIT_AFTER_CHANGE=180
REVERIFY_ATTEMPTS=10
REVERIFY_INTERVAL=2
MAX_CHANGE_RETRIES=5

TG_BOT_TOKEN="在此填入_BOT_TOKEN"
TG_CHAT_ID="在此填入_CHAT_ID"

LOG_DIR="/root/log/ip_monitor"
LOG_RETENTION_DAYS=7
mkdir -p "$LOG_DIR"
LOG_FILE="$LOG_DIR/$(date +%F).log"
### =========== 配置区 ===========

ts(){ date "+%F %T"; }

notify_tg(){
  local text="$1"
  [[ -n "$TG_BOT_TOKEN" && -n "$TG_CHAT_ID" ]] || return 0
  curl -sS "https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage" \
    -d "chat_id=${TG_CHAT_ID}" \
    --data-urlencode "text=${text}" >/dev/null || true
}

get_public_ip(){
  curl -fsS --max-time 4 https://ifconfig.me \
  || curl -fsS --max-time 4 https://api.ipify.org \
  || curl -fsS --max-time 4 https://ipinfo.io/ip \
  || echo "UNKNOWN"
}

# ===== 本机依赖自检 =====
require_cmd(){
  local cmd="$1" hint="$2"
  if ! command -v "$cmd" >/dev/null 2>&1; then
    echo "[$(ts)] 本机缺少依赖:$cmd"
    echo "[$(ts)] 请安装:$hint"
    notify_tg "❗本机缺少依赖:$cmd。建议安装:$hint"
    exit 10
  fi
}
check_local_deps(){
  require_cmd sshpass "apt-get update && apt-get install -y sshpass"
  require_cmd nc      "apt-get update && apt-get install -y netcat-openbsd"
}

# ===== 远端依赖自检 =====
check_remote_nc(){
  if sshpass -p "$CN_PASS" ssh -p "$CN_PORT" -o StrictHostKeyChecking=no \
      -o ConnectTimeout=5 -o BatchMode=no -o PreferredAuthentications=password \
      "${CN_USER}@${CN_HOST}" "command -v nc >/dev/null 2>&1"; then
    echo "[$(ts)] 探测节点 ${CN_HOST}:${CN_PORT} 已安装 nc"
  else
    local msg="❗探测节点 ${CN_HOST}:${CN_PORT} 未安装 nc。请执行:apt-get update && apt-get install -y netcat-openbsd"
    echo "[$(ts)] $msg"; notify_tg "$msg"; exit 11
  fi
}

# ===== 探测与判定 =====
probe_once_from_cn(){
  local ip="$1" port="$2"
  sshpass -p "$CN_PASS" ssh \
    -p "$CN_PORT" \
    -o StrictHostKeyChecking=no \
    -o ConnectTimeout=5 \
    -o BatchMode=no \
    -o PreferredAuthentications=password \
    "${CN_USER}@${CN_HOST}" \
    "nc -z -w3 ${ip} ${port}" >/dev/null 2>&1
}

# 任一端口在 tries 次内“全部失败”即返回 1(=需要换);否则返回 0(=不需要换)
probe_port_with_retries(){
  local ip="$1" port="$2" tries="$3" interval="$4" tag="$5"
  local i
  for i in $(seq 1 "$tries"); do
    if probe_once_from_cn "$ip" "$port"; then
      echo "[$(ts)] ${tag} 第 ${i}/${tries} 次:${ip}:${port} 可访问"
      return 0
    else
      echo "[$(ts)] ${tag} 第 ${i}/${tries} 次:${ip}:${port} 不可访问"
      sleep "$interval"
    fi
  done
  return 1
}

need_change_ip(){
  local ip="$1" tries="$2" interval="$3" tag="$4"
  local port
  for port in "${PORTS[@]}"; do
    echo "[$(ts)] ${tag} 检测 ${ip}:${port} ..."
    if probe_port_with_retries "$ip" "$port" "$tries" "$interval" "$tag"; then
      echo "[$(ts)] ${tag} 结论:${ip}:${port} 可访问"
    else
      echo "[$(ts)] ${tag} 结论:${ip}:${port} 在 ${tries} 次内均不通 → 需要换 IP"
      return 1
    fi
  done
  return 0
}

change_ip(){ curl -fsS --max-time 15 "$CHANGE_IP_URL" || true; }

clean_old_logs(){
  local count
  count=$(find "$LOG_DIR" -type f -name "*.log" -mtime +"$LOG_RETENTION_DAYS" 2>/dev/null | wc -l | awk '{print $1}')
  if [[ "$count" -gt 0 ]]; then
    find "$LOG_DIR" -type f -name "*.log" -mtime +"$LOG_RETENTION_DAYS" -delete 2>/dev/null || true
    echo "[$(ts)] 日志清理:删除 $count 个超过 ${LOG_RETENTION_DAYS} 天的日志文件"
    notify_tg "🧹 日志清理:删除 $count 个超过 ${LOG_RETENTION_DAYS} 天的日志($LOG_DIR)"
  else
    echo "[$(ts)] 日志清理:无超过 ${LOG_RETENTION_DAYS} 天的日志需要删除"
  fi
}

main(){
  check_local_deps
  check_remote_nc
  clean_old_logs

  local ip old_ip
  ip="$(get_public_ip)"; old_ip="$ip"
  echo "[$(ts)] 当前公网 IP: $ip"
  notify_tg "开始检测:VPS ${ip};端口:${PORTS[*]};规则:任一端口连续 ${ATTEMPTS} 次不通即更换 IP;探测节点:${CN_USER}@${CN_HOST}:${CN_PORT}。"

  # —— 首检:如果“不需要换”(返回0),直接通过并结束;否则进入换IP流程
  if need_change_ip "$ip" "$ATTEMPTS" "$SLEEP_BETWEEN" "首检"; then
    echo "[$(ts)] 首检通过:无需更换 IP。"
    notify_tg "✅ 首检通过:${ip} 端口组 ${PORTS[*]} 可访问,未换 IP。"
    return 0
  else
    notify_tg "⚠️ 首检不通过:${ip}(端口组:${PORTS[*]})。开始尝试更换 IP(最多 ${MAX_CHANGE_RETRIES} 次)..."
  fi

  # —— 更换与复检:最多 MAX_CHANGE_RETRIES 次
  local attempt
  for attempt in $(seq 1 "$MAX_CHANGE_RETRIES"); do
    echo "[$(ts)] 第 ${attempt}/${MAX_CHANGE_RETRIES} 次更换 IP ..."
    change_ip

    echo "[$(ts)] 等待 ${WAIT_AFTER_CHANGE}s 让新 IP 生效..."
    sleep "$WAIT_AFTER_CHANGE"

    ip="$(get_public_ip)"
    echo "[$(ts)] 更换完成:旧 IP:${old_ip};当前 IP:${ip}"
    notify_tg "♻️ 更换完成(第 ${attempt} 次):旧 IP:${old_ip};当前 IP:${ip};开始复检..."

    # 复检:如果“不需要换”(返回0),说明通过;否则继续下一轮或停止
    if need_change_ip "$ip" "$REVERIFY_ATTEMPTS" "$REVERIFY_INTERVAL" "复检"; then
      echo "[$(ts)] 复检通过:新 IP ${ip} 所有端口可访问。"
      notify_tg "✅ 复检通过:新 IP ${ip} 所有端口可访问。"
      exit 0
    else
      echo "[$(ts)] 复检不通过(第 ${attempt} 次更换后)。"
      notify_tg "❗复检不通过(第 ${attempt} 次更换后):${ip} 仍有端口不可访问。"
      old_ip="$ip"
      if [[ "$attempt" -eq "$MAX_CHANGE_RETRIES" ]]; then
        echo "[$(ts)] 已连续更换 ${MAX_CHANGE_RETRIES} 次仍不通,停止继续更换。"
        notify_tg "⛔ 已连续更换 ${MAX_CHANGE_RETRIES} 次仍不通,停止继续更换。请排查服务/防火墙/上游策略。"
        exit 3
      fi
    fi
  done
}

# 同时输出到屏幕和日志
main "$@" | tee -a "$LOG_FILE"

保存脚本到 /root/ip_probe.sh,授权:

chmod +x /root/ip_probe.sh

定时每3分钟运行一次检测

crontab -e
*/3 * * * * /root/ip_probe.sh >> /dev/null 2>&1

脚本说明

可手动更换的变量 / 参数(配置区)

脚本开头 ### =========== 配置区 =========== 里的变量,都是你后期可以直接改的:

端口组

PORTS=(59141 44299)

想加端口:PORTS=(59141 44299 50000 50001)

想只测一个端口:PORTS=(59141)

大陆探测节点

CN_HOST="xx.xx.xx"
CN_USER="root"
CN_PASS="你的root密码"
CN_PORT=54322

换主机:改 CN_HOST

不用 root:改 CN_USER(更安全),并给该用户 nc 权限即可

换 SSH 端口:改 CN_PORT

强烈建议后期改成密钥免密登录(避免明文密码),做法见后面建议

首检重试策略

ATTEMPTS=30
SLEEP_BETWEEN=1

每端口尝试次数、尝试间隔;

你要更保守可提到 50/1~2 秒;要更激进可降到 10/0.5 秒(但误判风险增大)。

换 IP 接口

CHANGE_IP_URL="http://100.100.101.101:8002/changeip"

如果换 IP 的 API 改了,或者需要带 token、POST JSON 等,直接改这里;

脚本目前用 curl -fsS --max-time 15 “CHANGEIPURL",如需POSTcurlfsSmaxtime15XPOSTHContentType:application/jsond"action":"change""CHANGE_IP_URL",如需 POST: curl -fsS --max-time 15 -X POST -H 'Content-Type: application/json' -d '{"action":"change"}' "CHANGE_IP_URL”

换 IP 后的复检策略

WAIT_AFTER_CHANGE=180       # 等 3 分钟
REVERIFY_ATTEMPTS=10        # 每端口 10 次
REVERIFY_INTERVAL=2         # 每次间隔 2s
MAX_CHANGE_RETRIES=5        # 最多换 5 次

网络收敛慢:把 WAIT_AFTER_CHANGE 提大(如 300 秒);

更严格复检:加大 REVERIFY_ATTEMPTS 或间隔;

更激进换 IP:把 MAX_CHANGE_RETRIES 提高(谨慎,避免死循环式频繁换 IP)。

Telegram 通知

TG_BOT_TOKEN="在此填入_BOT_TOKEN"
TG_CHAT_ID="在此填入_CHAT_ID"

换机器人/群:改这两项即可;

不想发通知:留空或注释掉这两行,通知函数内部会自动忽略。

日志

LOG_DIR="/root/log/ip_monitor"
LOG_RETENTION_DAYS=7

换路径:改 LOG_DIR;

保留时长:改 LOG_RETENTION_DAYS(单位:天)。

脚本做什么(一图读懂)

1.依赖自检

本机必须有:sshpass、nc(建议 netcat-openbsd 版)。

大陆探测节点(xx.xx.xx:54322)上必须有:nc。
—> 缺了就直接提示/发 TG,并退出,避免误判。

2.首检(当前 IP)

对端口组(默认 59141, 44299)逐个做连通性重试:每端口尝试 ATTEMPTS=30 次、间隔 SLEEP_BETWEEN=1s;

任一端口在 30 次内全部失败 ➜ 判定“不通,需要换 IP”;

只要每个端口里有一次成功,就视为该端口可用。

3.换 IP & 复检

首检不通过 → 调用 CHANGE_IP_URL 换 IP;

等 WAIT_AFTER_CHANGE=180s 再拿新 IP;

对端口组做复检(每端口 REVERIFY_ATTEMPTS=10 次、REVERIFY_INTERVAL=2s);

若仍判定“不通需要换 IP”,继续下一轮换 IP;最多 MAX_CHANGE_RETRIES=5 轮;

超过 5 次仍不通 → 停止,更明显地告警(日志 + Telegram)。

4.日志 & 通知

日志路径:/root/log/ip_monitor/YYYY-MM-DD.log;保留 LOG_RETENTION_DAYS=7 天;

每个关键节点都有 Telegram 通知(开始检测、换 IP、复检结果、停止等)。

0

评论区