#!/usr/bin/env bash
# ==============================================================================
# 脚本名称: check_time_wait_ports.sh
# 功能描述: 本机可用动态端口水位诊断与 TIME_WAIT 堆积安全巡检 (纯只读)
# 使用方式: 在网关或客户端宿主机以 root 权限执行
# ==============================================================================
set -o pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
PLAIN='\033[0m'
echo -e "${BLUE}================================================================${PLAIN}"
echo -e "${BLUE} 系统临时端口水位与 TIME_WAIT 拥塞自动化巡检 ${PLAIN}"
echo -e "${BLUE}================================================================${PLAIN}"
# 1. 提取当前系统配置的临时端口范围
PORT_RANGE=$(cat /proc/sys/net/ipv4/ip_local_port_range 2>/dev/null)
PORT_MIN=$(echo "$PORT_RANGE" | awk '{print $1}')
PORT_MAX=$(echo "$PORT_RANGE" | awk '{print $2}')
TOTAL_PORTS=$((PORT_MAX - PORT_MIN + 1))
echo -e "\n${YELLOW}[1/3] 系统动态临时端口池 (Ephemeral Ports) 容量分析...${PLAIN}"
echo -e " -> 端口分配范围: ${PORT_MIN} - ${PORT_MAX}"
echo -e " -> 可用端口总数: ${GREEN}${TOTAL_PORTS}${PLAIN} 个"
if [ "$TOTAL_PORTS" -lt 20000 ]; then
echo -e " -> ${RED}[WARN] 临时端口池范围较窄 (<20000),高并发下易耗尽,建议调整为 10240 65535。${PLAIN}"
fi
# 2. 统计当前 TCP 连接状态分布
echo -e "\n${YELLOW}[2/3] 实时统计 TCP 状态与端口占用水位...${PLAIN}"
SS_OUT=$(ss -s 2>/dev/null)
# 准确提取 ss -s 中的 estab 与 timewait 数值
ESTAB_COUNT=$(echo "$SS_OUT" | grep -o 'estab [0-9]*' | awk '{print $2}')
TW_COUNT=$(echo "$SS_OUT" | grep -o 'timewait [0-9]*' | awk '{print $2}')
ESTAB_COUNT=${ESTAB_COUNT:-0}
TW_COUNT=${TW_COUNT:-0}
echo -e " -> 当前活跃连接 (ESTABLISHED): ${GREEN}${ESTAB_COUNT}${PLAIN}"
echo -e " -> 等待回收连接 (TIME_WAIT) : ${YELLOW}${TW_COUNT}${PLAIN}"
if command -v bc &>/dev/null; then
USAGE_PCT=$(echo "scale=2; ($TW_COUNT / $TOTAL_PORTS) * 100" | bc 2>/dev/null)
# 修复了百分号转义乱码
echo -e " -> TIME_WAIT 占临时端口池比例: ${YELLOW}${USAGE_PCT}%${PLAIN}"
if (( $(echo "$USAGE_PCT > 80.0" | bc -l) )); then
# 修复了百分号转义乱码
echo -e " -> ${RED}[ALERT] TIME_WAIT 占用已超过临时端口总量的 80%!${PLAIN}"
echo -e " -> ${RED}[FATAL] 极易触发 Cannot assign requested address 报错导致 502!${PLAIN}"
else
echo -e " -> ${GREEN}[OK] 当前临时端口使用率处于安全水位。${PLAIN}"
fi
fi
# 3. 检查内核端口复用参数
echo -e "\n${YELLOW}[3/3] 检查内核层 TIME_WAIT 端口复用与安全参数...${PLAIN}"
REUSE_STATUS=$(cat /proc/sys/net/ipv4/tcp_tw_reuse 2>/dev/null)
# 修复了逻辑或乱码
if [ "$REUSE_STATUS" == "1" ] || [ "$REUSE_STATUS" == "2" ]; then
echo -e " -> tcp_tw_reuse : ${GREEN}已开启 (值为 ${REUSE_STATUS})${PLAIN}"
echo -e " -> ${GREEN}[OK] 系统支持在发起出站连接时安全复用 TIME_WAIT 端口。${PLAIN}"
else
echo -e " -> tcp_tw_reuse : ${RED}未开启 (值为 ${REUSE_STATUS:-0})${PLAIN}"
echo -e " -> ${YELLOW}[建议] 若发生端口耗尽告警,可执行 sysctl -w net.ipv4.tcp_tw_reuse=1 应急恢复。${PLAIN}"
fi
RECYCLE_STATUS=$(cat /proc/sys/net/ipv4/tcp_tw_recycle 2>/dev/null || echo "not_exist")
if [ "$RECYCLE_STATUS" == "1" ]; then
echo -e " -> tcp_tw_recycle : ${RED}已开启 (高危配置!)${PLAIN}"
echo -e " -> ${RED}[DANGER] tcp_tw_recycle 在 NAT 环境下会导致严重丢包,请立即执行 sysctl -w net.ipv4.tcp_tw_recycle=0 关闭!${PLAIN}"
fi
echo -e "\n${BLUE}================================================================${PLAIN}"
echo -e "${BLUE}巡检完毕。若需根治 TIME_WAIT 堆积,请核查 Nginx upstream keepalive 及应用层连接池配置。${PLAIN}"
echo -e "${BLUE}================================================================${PLAIN}"