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

# ===== 基础参数区（支持环境变量覆盖）=====
NIC="${NIC:-}"
MAIN_IP="${MAIN_IP:-}"
VIPS_CSV="${VIPS_CSV:-}"
DEFAULT_VIPS=(10.0.0.11 10.0.0.12 10.0.0.13 10.0.0.14 10.0.0.15 10.0.0.16 10.0.0.17 10.0.0.18 10.0.0.19)
# 默认全自动：自动识别 10IP 或 2IP
TOTAL_IPS="${TOTAL_IPS:-auto}"
AUTO_PICK_VIPS="${AUTO_PICK_VIPS:-1}"
VIP_SCAN_CSV="${VIP_SCAN_CSV:-10.0.0.11,10.0.0.12,10.0.0.13,10.0.0.14,10.0.0.15,10.0.0.16,10.0.0.17,10.0.0.18,10.0.0.19}"
SOCKS_USER_DEFAULT="${SOCKS_USER:-root}"
SOCKS_PASS_DEFAULT="${SOCKS_PASS:-wawacloud}"
SOCKS_PORT_DEFAULT="${SOCKS_PORT:-23456}"
OUTPUT_FILE="${OUTPUT_FILE:-/root/socks5_list.txt}"
VIP_DIAG_FILE="${VIP_DIAG_FILE:-/root/vip_detect.txt}"
XRAY_BIN="${XRAY_BIN:-/usr/local/bin/xray}"
XRAY_URL="${XRAY_URL:-http://wawaok.cn/static/xray}"
L2TP_PSK="${L2TP_PSK:-wawacloud}"
L2TP_PASS="${L2TP_PASS:-wawacloud}"
L2TP_LOCAL_IP="${L2TP_LOCAL_IP:-10.99.0.1}"
L2TP_POOL="${L2TP_POOL:-10.99.0.10-10.99.0.200}"
L2TP_NET_CIDR="${L2TP_NET_CIDR:-10.99.0.0/24}"
L2TP_USERS_FILE="${L2TP_USERS_FILE:-/root/l2tp_users.txt}"
L2TP_USER_MAP_FILE="${L2TP_USER_MAP_FILE:-/root/l2tp_user_map.txt}"
L2TP_CLIENT_IP_PREFIX="${L2TP_CLIENT_IP_PREFIX:-10.99.0}"
L2TP_CLIENT_IP_START="${L2TP_CLIENT_IP_START:-11}"

# 必须使用 root 执行，否则无法写系统配置和启动服务
if [[ $EUID -ne 0 ]]; then
  echo "Please run as root"
  exit 1
fi

# 自动识别默认出口网卡
if [[ -z "$NIC" ]]; then
  NIC="$(ip -4 route show default | awk 'NR==1 {print $5}')"
fi

if ! ip link show "$NIC" >/dev/null 2>&1; then
  echo "NIC $NIC not found"
  exit 1
fi

# 自动识别主网卡 IPv4（用于 user1/L2TP 主出口）
if [[ -z "$MAIN_IP" ]]; then
  MAIN_IP="$(ip -o -4 addr show dev "$NIC" scope global | awk 'NR==1 {print $4}' | cut -d/ -f1)"
fi

if [[ -z "$MAIN_IP" ]]; then
  MAIN_IP="$(ip -4 route get 1.1.1.1 2>/dev/null | awk '/src/ {for(i=1;i<=NF;i++) if($i==\"src\"){print $(i+1); exit}}')"
fi

if [[ -z "$MAIN_IP" ]]; then
  echo "MAIN_IP auto detect failed"
  exit 1
fi

# 统一公网探测函数：绑定源IP请求多个外部接口，拿到真实出口公网IP
probe_public_ip_common() {
  local src_ip="$1"
  local result=""
  local urls=(
    "http://whatismyip.akamai.com"
    "https://api.ipify.org"
    "https://ipv4.icanhazip.com"
  )

  for url in "${urls[@]}"; do
    result="$(curl -4fsS --interface "$src_ip" --connect-timeout 5 --max-time 10 "$url" 2>/dev/null | tr -d '\r\n[:space:]')"
    if [[ "$result" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
      echo "$result"
      return 0
    fi
  done
  return 1
}

probe_public_ip_default() {
  local result=""
  local urls=(
    "http://whatismyip.akamai.com"
    "https://api.ipify.org"
    "https://ipv4.icanhazip.com"
  )

  for url in "${urls[@]}"; do
    result="$(curl -4fsS --connect-timeout 5 --max-time 10 "$url" 2>/dev/null | tr -d '\r\n[:space:]')"
    if [[ "$result" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
      echo "$result"
      return 0
    fi
  done
  return 1
}

# 用于前置快速筛选可用 VIP
probe_public_ip_quick() {
  probe_public_ip_common "$1"
}

add_ip() {
  local ip="$1"
  if ! ip -o -4 addr show dev "$NIC" | awk '{print $4}' | cut -d/ -f1 | grep -qx "$ip"; then
    ip addr add "${ip}/32" dev "$NIC" 2>/dev/null || true
  fi
}

REQUESTED_TOTAL_IPS="${TOTAL_IPS}"
TARGET_VIP_COUNT=0
EFFECTIVE_TOTAL_IPS=0
MODE_DESC=""
if [[ "${TOTAL_IPS}" != "auto" ]]; then
  echo "${TOTAL_IPS}" | grep -Eq '^[0-9]+$' || { echo "TOTAL_IPS must be numeric or 'auto'"; exit 1; }
  [[ "${TOTAL_IPS}" -ge 2 ]] || { echo "TOTAL_IPS must be >= 2"; exit 1; }
  TARGET_VIP_COUNT=$((TOTAL_IPS - 1))
fi

# 候选 VIP 列表：
# 1) VIPS_CSV 手动指定
# 2) AUTO_PICK_VIPS=1 用 VIP_SCAN_CSV 作为候选池
# 3) DEFAULT_VIPS 固定默认列表
VIP_CANDIDATES=()
if [[ -n "$VIPS_CSV" ]]; then
  read -r -a VIP_CANDIDATES <<<"${VIPS_CSV//,/ }"
elif [[ "$AUTO_PICK_VIPS" == "1" ]]; then
  read -r -a VIP_CANDIDATES <<<"${VIP_SCAN_CSV//,/ }"
else
  VIP_CANDIDATES=("${DEFAULT_VIPS[@]}")
fi

# 先把候选 VIP 全部挂到网卡上，满足天翼云“先添加到系统里再激活”的规则
ACTIVATION_VIPS=()
for cand in "${VIP_CANDIDATES[@]}"; do
  already_added=0
  [[ -n "$cand" ]] || continue
  [[ "$cand" == "$MAIN_IP" ]] && continue
  for existing in "${ACTIVATION_VIPS[@]-}"; do
    if [[ "$existing" == "$cand" ]]; then
      already_added=1
      break
    fi
  done
  if [[ "$already_added" -eq 0 ]]; then
    ACTIVATION_VIPS+=("$cand")
    add_ip "$cand"
  fi
done

# 再从已添加的候选 VIP 中探测哪些是真正可用的
VIPS=()
declare -A VIP_PUB_MAP
for cand in "${ACTIVATION_VIPS[@]}"; do
  if pub="$(probe_public_ip_quick "$cand" || true)" && [[ -n "$pub" ]]; then
    VIPS+=("$cand")
    VIP_PUB_MAP["$cand"]="$pub"
    echo "✅ 可用VIP: $cand -> $pub"
  else
    VIP_PUB_MAP["$cand"]="不可用"
    echo "⚠️ 未激活或不可用VIP: $cand"
  fi
done

USABLE_VIP_COUNT="${#VIPS[@]}"
if [[ "${TOTAL_IPS}" == "auto" ]]; then
  if [[ "${USABLE_VIP_COUNT}" -ge 9 ]]; then
    TARGET_VIP_COUNT=9
    EFFECTIVE_TOTAL_IPS=10
    MODE_DESC="auto-10ip"
  elif [[ "${USABLE_VIP_COUNT}" -ge 1 ]]; then
    TARGET_VIP_COUNT=1
    EFFECTIVE_TOTAL_IPS=2
    MODE_DESC="auto-2ip"
  else
    echo "No usable VIP found after activation."
    echo "请先在天翼云控制台绑定/激活虚拟IP，再重新运行。"
    exit 1
  fi
  VIPS=("${VIPS[@]:0:$TARGET_VIP_COUNT}")
  echo "✅ 自动识别模式: ${MODE_DESC}"
else
  if [[ "${#VIPS[@]}" -gt "$TARGET_VIP_COUNT" ]]; then
    VIPS=("${VIPS[@]:0:$TARGET_VIP_COUNT}")
  fi

  if [[ "${#VIPS[@]}" -lt "$TARGET_VIP_COUNT" ]]; then
    if [[ "${#VIPS[@]}" -ge 1 ]]; then
      echo "⚠️ 可用VIP不足，已自动降级为 ${#VIPS[@]} 个VIP（总IP=$(( ${#VIPS[@]} + 1 ))）"
      TARGET_VIP_COUNT="${#VIPS[@]}"
    else
      echo "No usable VIP found after activation."
      echo "请先在天翼云控制台绑定/激活虚拟IP，再重新运行。"
      exit 1
    fi
  fi
  EFFECTIVE_TOTAL_IPS=$((TARGET_VIP_COUNT + 1))
  MODE_DESC="manual-${REQUESTED_TOTAL_IPS}ip"
fi

# ALL_IPS 顺序非常关键：
# [0] 主 IP（对应 user1 出口）
# [1..] 其余 VIP（对应 user2.. 出口）
ALL_IPS=("$MAIN_IP")
for ip in "${VIPS[@]}"; do
  if [[ "$ip" != "$MAIN_IP" ]]; then
    ALL_IPS+=("$ip")
  fi
done

if [[ "${#ALL_IPS[@]}" -lt 2 ]]; then
  echo "Need at least MAIN_IP + 1 VIP. Set VIPS_CSV if needed."
  exit 1
fi

echo "Detected NIC: $NIC"
echo "Detected MAIN_IP: $MAIN_IP"
echo "Mode: AUTO_PICK_VIPS=${AUTO_PICK_VIPS}, REQUESTED_TOTAL_IPS=${REQUESTED_TOTAL_IPS}, EFFECTIVE_TOTAL_IPS=${EFFECTIVE_TOTAL_IPS}, MODE=${MODE_DESC}"
echo "Activation VIPs: ${ACTIVATION_VIPS[*]:-none}"
echo "Usable VIPs: ${VIPS[*]:-none}"

umask 077
{
  echo "NIC=${NIC}"
  echo "MAIN_IP=${MAIN_IP}"
  echo "REQUESTED_TOTAL_IPS=${REQUESTED_TOTAL_IPS}"
  echo "EFFECTIVE_TOTAL_IPS=${EFFECTIVE_TOTAL_IPS}"
  echo "MODE=${MODE_DESC}"
  echo "AUTO_PICK_VIPS=${AUTO_PICK_VIPS}"
  echo ""
  echo "[Activation VIPs]"
  printf '%s\n' "${ACTIVATION_VIPS[@]}"
  echo ""
  echo "[Probe Results]"
  for cand in "${ACTIVATION_VIPS[@]}"; do
    echo "${cand} -> ${VIP_PUB_MAP[$cand]}"
  done
  echo ""
  echo "[Usable VIPs]"
  for cand in "${VIPS[@]}"; do
    echo "${cand} -> ${VIP_PUB_MAP[$cand]}"
  done
} > "$VIP_DIAG_FILE"
echo "VIP detect file: ${VIP_DIAG_FILE}"

# 交互输入 SOCKS5 参数（非交互时用默认值）
if [[ -t 0 ]]; then
  read -r -p "请输入 SOCKS5 用户名(默认 ${SOCKS_USER_DEFAULT})： " USERNAME
  SOCKS_USER="${USERNAME:-$SOCKS_USER_DEFAULT}"

  read -r -p "请输入 SOCKS5 密码(默认 ${SOCKS_PASS_DEFAULT})： " PASSWORD
  SOCKS_PASS="${PASSWORD:-$SOCKS_PASS_DEFAULT}"

  read -r -p "请输入 SOCKS5 端口(默认 ${SOCKS_PORT_DEFAULT})： " PORT
  SOCKS_PORT="${PORT:-$SOCKS_PORT_DEFAULT}"
else
  SOCKS_USER="$SOCKS_USER_DEFAULT"
  SOCKS_PASS="$SOCKS_PASS_DEFAULT"
  SOCKS_PORT="$SOCKS_PORT_DEFAULT"
fi

echo "${SOCKS_PORT}" | grep -Eq '^[0-9]+$' || { echo "错误：端口必须是数字。"; exit 1; }
[ "${SOCKS_PORT}" -ge 1 ] && [ "${SOCKS_PORT}" -le 65535 ] || { echo "错误：端口必须在 1-65535。"; exit 1; }

# 生成开机补 VIP 脚本，重启后仍然先把所有候选 VIP 挂上去做激活
VIPS_BASH="$(printf '%s ' "${ACTIVATION_VIPS[@]}")"
cat >/usr/local/sbin/ct-vip-apply.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

NIC="${NIC:-$(ip -4 route show default | awk 'NR==1 {print $5}')}"
if [[ -z "$NIC" ]]; then
  echo "Default NIC not found"
  exit 1
fi

VIPS=(__VIPS_PLACEHOLDER__)

for ip in "${VIPS[@]}"; do
  ip -o -4 addr show dev "$NIC" | awk '{print $4}' | cut -d/ -f1 | grep -qx "$ip" || ip addr add "${ip}/32" dev "$NIC"
done
EOF
sed -i "s#__VIPS_PLACEHOLDER__#${VIPS_BASH}#g" /usr/local/sbin/ct-vip-apply.sh
chmod +x /usr/local/sbin/ct-vip-apply.sh

# 注册 VIP 自启服务
cat >/etc/systemd/system/ct-vip.service <<'EOF'
[Unit]
Description=Apply CT VIPs
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/ct-vip-apply.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now ct-vip.service

# 网络内核参数：开启转发，关闭严格反向校验，适配多出口场景
cat >/etc/sysctl.d/99-socks-l2tp.conf <<EOF
net.ipv4.ip_forward=1
net.ipv4.conf.all.rp_filter=0
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.${NIC}.rp_filter=0
net.ipv4.conf.all.accept_redirects=0
net.ipv4.conf.all.send_redirects=0
EOF
sysctl --system >/dev/null

install_pkgs() {
  if command -v apt-get >/dev/null 2>&1; then
    apt_ok=0
    for n in 1 2 3; do
      apt-get update && { apt_ok=1; break; }
      sleep $((n * 3))
    done
    if [ "$apt_ok" != "1" ] && grep -Rqs "mirrors.ctyun.cn" /etc/apt/sources.list /etc/apt/sources.list.d 2>/dev/null; then
      sed -i.bak -e "s#http://mirrors.ctyun.cn/debian-security#http://deb.debian.org/debian-security#g" -e "s#http://mirrors.ctyun.cn/debian#http://deb.debian.org/debian#g" /etc/apt/sources.list /etc/apt/sources.list.d/*.list 2>/dev/null || true
      apt-get clean || true
      rm -rf /var/lib/apt/lists/*
      for n in 1 2 3; do
        apt-get update && { apt_ok=1; break; }
        sleep $((n * 3))
      done
    fi
    [ "$apt_ok" = "1" ] || exit 1
    DEBIAN_FRONTEND=noninteractive apt-get install -y "$@"
    return 0
  fi

  if command -v dnf >/dev/null 2>&1; then
    dnf install -y "$@"
    return 0
  fi

  if command -v yum >/dev/null 2>&1; then
    yum install -y "$@"
    return 0
  fi

  echo "No supported package manager found (apt-get/dnf/yum)"
  exit 1
}

if command -v dnf >/dev/null 2>&1; then
  dnf install -y epel-release >/dev/null 2>&1 || true
elif command -v yum >/dev/null 2>&1; then
  yum install -y epel-release >/dev/null 2>&1 || true
fi

if ! command -v curl >/dev/null 2>&1; then
  install_pkgs curl
fi

if command -v apt-get >/dev/null 2>&1; then
  install_pkgs strongswan xl2tpd ppp iptables strongswan-starter strongswan-charon libstrongswan-standard-plugins
else
  install_pkgs strongswan xl2tpd ppp iptables iptables-services
fi

install_xray() {
  if command -v xray >/dev/null 2>&1; then
    XRAY_BIN="$(command -v xray)"
    return 0
  fi

  if [[ -x "$XRAY_BIN" ]]; then
    return 0
  fi

  echo "Downloading xray from: ${XRAY_URL}"
  curl -fsSL --connect-timeout 15 --max-time 120 "$XRAY_URL" -o "$XRAY_BIN"
  chmod 0755 "$XRAY_BIN"
}

install_xray
if ! [[ -x "$XRAY_BIN" ]]; then
  echo "xray install failed"
  exit 1
fi
if ! "$XRAY_BIN" version >/dev/null 2>&1; then
  echo "xray binary invalid: $XRAY_BIN"
  exit 1
fi

# ===== 生成 Xray 配置 =====
# 每个入口监听一个 IP 的同一端口，再按入口 tag 路由到对应 sendThrough 出口 IP
mkdir -p /etc/xray
CONFIG_FILE="/etc/xray/config.json"
{
  echo "{"
  echo "  \"log\": {\"loglevel\": \"warning\"},"
  echo "  \"inbounds\": ["
  first=1
  for ip in "${ALL_IPS[@]}"; do
    in_tag="socks_${ip//./_}"
    out_tag="out_${ip//./_}"
    if [[ $first -eq 0 ]]; then
      echo "    ,"
    fi
    cat <<EOF
    {
      "tag": "${in_tag}",
      "listen": "${ip}",
      "port": ${SOCKS_PORT},
      "protocol": "socks",
      "settings": {
        "auth": "password",
        "accounts": [
          {"user": "${SOCKS_USER}", "pass": "${SOCKS_PASS}"}
        ],
        "udp": false
      }
    }
EOF
    first=0
  done
  echo "  ],"
  echo "  \"outbounds\": ["
  first=1
  for ip in "${ALL_IPS[@]}"; do
    out_tag="out_${ip//./_}"
    if [[ $first -eq 0 ]]; then
      echo "    ,"
    fi
    cat <<EOF
    {
      "tag": "${out_tag}",
      "protocol": "freedom",
      "settings": {},
      "sendThrough": "${ip}"
    }
EOF
    first=0
  done
  echo "  ],"
  echo "  \"routing\": {"
  echo "    \"domainStrategy\": \"AsIs\","
  echo "    \"rules\": ["
  first=1
  for ip in "${ALL_IPS[@]}"; do
    in_tag="socks_${ip//./_}"
    out_tag="out_${ip//./_}"
    if [[ $first -eq 0 ]]; then
      echo "      ,"
    fi
    cat <<EOF
      {
        "type": "field",
        "inboundTag": ["${in_tag}"],
        "outboundTag": "${out_tag}"
      }
EOF
    first=0
  done
  echo "    ]"
  echo "  }"
  echo "}"
} > "$CONFIG_FILE"

cat >/etc/systemd/system/xray-socks.service <<EOF
[Unit]
Description=Xray Multi-IP SOCKS5
After=network-online.target ct-vip.service
Wants=network-online.target ct-vip.service

[Service]
Type=simple
ExecStart=${XRAY_BIN} run -config ${CONFIG_FILE}
ExecReload=/bin/kill -HUP \$MAINPID
Restart=always
RestartSec=2
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl disable --now 3proxy >/dev/null 2>&1 || true
systemctl enable --now xray-socks
sleep 1

# 确认 SOCKS 端口已监听
if ! ss -lntp | grep -Eq ":${SOCKS_PORT}\b"; then
  echo "xray is running but no SOCKS listen ports found."
  echo "Check logs: journalctl -u xray-socks -n 80 --no-pager"
  echo "Config: ${CONFIG_FILE}"
  exit 1
fi

cat >/etc/ipsec.conf <<EOF
config setup
  uniqueids=no

conn L2TP-PSK
  auto=add
  keyexchange=ikev1
  authby=secret
  type=transport
  left=%any
  leftprotoport=17/1701
  right=%any
  rightprotoport=17/%any
  ike=aes128-sha1-modp1024!
  esp=aes128-sha1!
  rekey=no
  dpddelay=30
  dpdtimeout=120
  dpdaction=clear
  forceencaps=yes
EOF

cat >/etc/ipsec.secrets <<EOF
%any %any : PSK "${L2TP_PSK}"
EOF
chmod 600 /etc/ipsec.secrets

mkdir -p /etc/xl2tpd
cat >/etc/xl2tpd/xl2tpd.conf <<EOF
[global]
port = 1701

[lns default]
ip range = ${L2TP_POOL}
local ip = ${L2TP_LOCAL_IP}
require chap = yes
refuse pap = yes
require authentication = yes
name = l2tpd
pppoptfile = /etc/ppp/options.xl2tpd
length bit = yes
EOF

mkdir -p /etc/ppp
cat >/etc/ppp/options.xl2tpd <<'EOF'
require-mschap-v2
refuse-pap
refuse-chap
refuse-mschap
auth
ms-dns 223.5.5.5
ms-dns 119.29.29.29
nodefaultroute
nobsdcomp
mtu 1410
mru 1410
connect-delay 5000
name l2tpd
EOF

mkdir -p /etc/strongswan.d/charon
cat >/etc/strongswan.d/charon/socket-default.conf <<'EOF'
charon {
  plugins {
    socket-default {
      load = yes
    }
  }
}
EOF
cat >/etc/strongswan.d/charon/kernel-netlink.conf <<'EOF'
charon {
  plugins {
    kernel-netlink {
      load = yes
    }
  }
}
EOF

cat >/etc/ppp/chap-secrets <<'EOF'
# client    server    secret    IP addresses
EOF
umask 077
: > "$L2TP_USERS_FILE"
: > "$L2TP_USER_MAP_FILE"
echo "${L2TP_CLIENT_IP_START}" | grep -Eq '^[0-9]+$' || { echo "L2TP_CLIENT_IP_START must be numeric"; exit 1; }
USER_COUNT="${#ALL_IPS[@]}"
LAST_CLIENT_OCTET=$((L2TP_CLIENT_IP_START + USER_COUNT - 1))
if [[ "$LAST_CLIENT_OCTET" -gt 254 ]]; then
  echo "L2TP client IP range overflow: ${L2TP_CLIENT_IP_PREFIX}.${L2TP_CLIENT_IP_START}-${L2TP_CLIENT_IP_PREFIX}.${LAST_CLIENT_OCTET}"
  exit 1
fi

# L2TP 用户与固定出口映射：
# user1 -> ALL_IPS[0] (主IP)
# user2 -> ALL_IPS[1]
# user3 -> ALL_IPS[2] ...
for i in $(seq 1 "$USER_COUNT"); do
  user="user${i}"
  client_octet=$((L2TP_CLIENT_IP_START + i - 1))
  client_ip="${L2TP_CLIENT_IP_PREFIX}.${client_octet}"
  exit_ip="${ALL_IPS[$((i - 1))]}"
  echo "\"${user}\" l2tpd \"${L2TP_PASS}\" ${client_ip}" >> /etc/ppp/chap-secrets
  echo "${user}/${L2TP_PASS}" >> "$L2TP_USERS_FILE"
  echo "${user}/${client_ip}/${exit_ip}" >> "$L2TP_USER_MAP_FILE"
done
chmod 600 /etc/ppp/chap-secrets "$L2TP_USERS_FILE" "$L2TP_USER_MAP_FILE"

cat >/usr/local/sbin/ct-l2tp-fw.sh <<EOF
#!/usr/bin/env bash
set -euo pipefail

NIC="${NIC}"
L2TP_NET_CIDR="${L2TP_NET_CIDR}"
SNAT_CHAIN="CT_L2TP_SNAT"
MAIN_IP="${MAIN_IP}"

add_rule() {
  local table="\$1"
  shift
  if [[ -n "\$table" ]]; then
    iptables -t "\$table" -C "\$@" 2>/dev/null || iptables -t "\$table" -A "\$@"
  else
    iptables -C "\$@" 2>/dev/null || iptables -A "\$@"
  fi
}

del_rule_all() {
  local table="\$1"
  shift
  while true; do
    if [[ -n "\$table" ]]; then
      iptables -t "\$table" -D "\$@" 2>/dev/null || break
    else
      iptables -D "\$@" 2>/dev/null || break
    fi
  done
}

# 基础放行规则 + 转发规则
add_rule "" INPUT -p udp --dport 500 -j ACCEPT
add_rule "" INPUT -p udp --dport 4500 -j ACCEPT
add_rule "" INPUT -p udp --dport 1701 -j ACCEPT
add_rule "" INPUT -i ppp+ -j ACCEPT
add_rule "" FORWARD -s "\$L2TP_NET_CIDR" -j ACCEPT
add_rule "" FORWARD -d "\$L2TP_NET_CIDR" -m state --state RELATED,ESTABLISHED -j ACCEPT

# 清理旧 MASQUERADE，改用自定义 SNAT 链来做“按用户固定出口IP”
del_rule_all "nat" POSTROUTING -s "\$L2TP_NET_CIDR" -o "\$NIC" -j MASQUERADE
iptables -t nat -N "\$SNAT_CHAIN" 2>/dev/null || true
iptables -t nat -F "\$SNAT_CHAIN"
add_rule "nat" POSTROUTING -s "\$L2TP_NET_CIDR" -o "\$NIC" -j "\$SNAT_CHAIN"
EOF
# 逐用户写 SNAT 规则：客户端源IP -> 对应出口IP
for i in $(seq 1 "$USER_COUNT"); do
  client_octet=$((L2TP_CLIENT_IP_START + i - 1))
  client_ip="${L2TP_CLIENT_IP_PREFIX}.${client_octet}"
  exit_ip="${ALL_IPS[$((i - 1))]}"
  echo "iptables -t nat -A \"\$SNAT_CHAIN\" -s \"${client_ip}\" -j SNAT --to-source \"${exit_ip}\"" >> /usr/local/sbin/ct-l2tp-fw.sh
done
echo "iptables -t nat -A \"\$SNAT_CHAIN\" -j SNAT --to-source \"\$MAIN_IP\"" >> /usr/local/sbin/ct-l2tp-fw.sh
chmod +x /usr/local/sbin/ct-l2tp-fw.sh

cat >/etc/systemd/system/ct-l2tp-fw.service <<'EOF'
[Unit]
Description=Apply L2TP firewall rules
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/ct-l2tp-fw.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF

IPSEC_SERVICE=""
if systemctl list-unit-files | awk '{print $1}' | grep -qx "strongswan-starter.service"; then
  IPSEC_SERVICE="strongswan-starter"
  systemctl enable --now "${IPSEC_SERVICE}"
  systemctl restart "${IPSEC_SERVICE}"
elif systemctl list-unit-files | awk '{print $1}' | grep -qx "strongswan.service"; then
  IPSEC_SERVICE="strongswan"
  systemctl enable --now "${IPSEC_SERVICE}"
  systemctl restart "${IPSEC_SERVICE}"
else
  ipsec restart >/dev/null 2>&1 || true
fi

if [[ -n "$IPSEC_SERVICE" ]] && ! systemctl is-active --quiet "${IPSEC_SERVICE}"; then
  echo "IPsec service failed: ${IPSEC_SERVICE}"
  journalctl -u "${IPSEC_SERVICE}" -n 80 --no-pager || true
  exit 1
fi

systemctl enable --now xl2tpd
systemctl restart xl2tpd
systemctl daemon-reload
systemctl enable --now ct-l2tp-fw

# 检查 L2TP/IPsec 关键 UDP 端口
if ! ss -lun | grep -Eq ':(500|4500|1701)\b'; then
  echo "Warning: L2TP/IPsec UDP ports are not all listening yet."
  echo "Check logs: journalctl -u xl2tpd -u strongswan-starter -u strongswan -n 80 --no-pager"
fi

# 安装管理菜单：输入 wawacloud 可随时修改账号/密码/端口/PSK 并重载服务
cat >/usr/local/bin/wawacloud <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

XRAY_CONFIG="/etc/xray/config.json"
L2TP_CHAP="/etc/ppp/chap-secrets"
IPSEC_SECRET="/etc/ipsec.secrets"
L2TP_MAP="/root/l2tp_user_map.txt"

if [[ $EUID -ne 0 ]]; then
  echo "请使用 root 运行: sudo wawacloud"
  exit 1
fi

require_file() {
  local f="$1"
  [[ -f "$f" ]] || { echo "缺少文件: $f"; exit 1; }
}

get_all_ips() {
  mapfile -t ALL_IPS < <(sed -n 's/.*"listen":[[:space:]]*"\([^"]*\)".*/\1/p' "$XRAY_CONFIG" | awk '!seen[$0]++')
  if [[ "${#ALL_IPS[@]}" -eq 0 && -f "$L2TP_MAP" ]]; then
    mapfile -t ALL_IPS < <(awk -F/ 'NF>=3 {print $3}' "$L2TP_MAP")
  fi
  if [[ "${#ALL_IPS[@]}" -eq 0 ]]; then
    echo "无法识别 ALL_IPS（xray 配置中没有 listen IP）"
    exit 1
  fi
}

load_current() {
  require_file "$XRAY_CONFIG"
  require_file "$L2TP_CHAP"
  require_file "$IPSEC_SECRET"

  CUR_SOCKS_PORT="$(sed -n 's/.*"port":[[:space:]]*\([0-9][0-9]*\).*/\1/p' "$XRAY_CONFIG" | head -n1)"
  CUR_SOCKS_USER="$(sed -n 's/.*"user":[[:space:]]*"\([^"]*\)".*/\1/p' "$XRAY_CONFIG" | head -n1)"
  CUR_SOCKS_PASS="$(sed -n 's/.*"pass":[[:space:]]*"\([^"]*\)".*/\1/p' "$XRAY_CONFIG" | head -n1)"
  CUR_L2TP_PASS="$(awk -F'"' '/^"user[0-9]+"/ {print $4; exit}' "$L2TP_CHAP")"
  CUR_PSK="$(sed -n 's/^.*PSK[[:space:]]*"\([^"]*\)".*$/\1/p' "$IPSEC_SECRET" | head -n1)"

  CUR_SOCKS_PORT="${CUR_SOCKS_PORT:-23456}"
  CUR_SOCKS_USER="${CUR_SOCKS_USER:-root}"
  CUR_SOCKS_PASS="${CUR_SOCKS_PASS:-wawacloud}"
  CUR_L2TP_PASS="${CUR_L2TP_PASS:-wawacloud}"
  CUR_PSK="${CUR_PSK:-wawacloud}"
}

validate_port() {
  local p="$1"
  echo "$p" | grep -Eq '^[0-9]+$' || { echo "端口必须是数字"; exit 1; }
  [[ "$p" -ge 1 && "$p" -le 65535 ]] || { echo "端口范围必须是 1-65535"; exit 1; }
}

write_xray_config() {
  local user="$1"
  local pass="$2"
  local port="$3"
  local tmp_file
  tmp_file="$(mktemp)"

  get_all_ips
  {
    echo "{"
    echo "  \"log\": {\"loglevel\": \"warning\"},"
    echo "  \"inbounds\": ["
    first=1
    for ip in "${ALL_IPS[@]}"; do
      in_tag="socks_${ip//./_}"
      if [[ $first -eq 0 ]]; then
        echo "    ,"
      fi
      cat <<EOC
    {
      "tag": "${in_tag}",
      "listen": "${ip}",
      "port": ${port},
      "protocol": "socks",
      "settings": {
        "auth": "password",
        "accounts": [
          {"user": "${user}", "pass": "${pass}"}
        ],
        "udp": false
      }
    }
EOC
      first=0
    done
    echo "  ],"
    echo "  \"outbounds\": ["
    first=1
    for ip in "${ALL_IPS[@]}"; do
      out_tag="out_${ip//./_}"
      if [[ $first -eq 0 ]]; then
        echo "    ,"
      fi
      cat <<EOC
    {
      "tag": "${out_tag}",
      "protocol": "freedom",
      "settings": {},
      "sendThrough": "${ip}"
    }
EOC
      first=0
    done
    echo "  ],"
    echo "  \"routing\": {"
    echo "    \"domainStrategy\": \"AsIs\","
    echo "    \"rules\": ["
    first=1
    for ip in "${ALL_IPS[@]}"; do
      in_tag="socks_${ip//./_}"
      out_tag="out_${ip//./_}"
      if [[ $first -eq 0 ]]; then
        echo "      ,"
      fi
      cat <<EOC
      {
        "type": "field",
        "inboundTag": ["${in_tag}"],
        "outboundTag": "${out_tag}"
      }
EOC
      first=0
    done
    echo "    ]"
    echo "  }"
    echo "}"
  } > "$tmp_file"

  mv "$tmp_file" "$XRAY_CONFIG"
}

update_l2tp_pass() {
  local new_pass="$1"
  local tmp_file
  tmp_file="$(mktemp)"
  awk -v p="$new_pass" 'BEGIN{FS=OFS="\""} /^"user[0-9]+"/ { $4=p } { print }' "$L2TP_CHAP" > "$tmp_file"
  mv "$tmp_file" "$L2TP_CHAP"
  chmod 600 "$L2TP_CHAP"
}

update_psk() {
  local new_psk="$1"
  echo "%any %any : PSK \"${new_psk}\"" > "$IPSEC_SECRET"
  chmod 600 "$IPSEC_SECRET"
}

restart_stack() {
  systemctl daemon-reload
  systemctl enable ct-vip xray-socks xl2tpd ct-l2tp-fw wawacloud-ensure >/dev/null 2>&1 || true

  if systemctl list-unit-files | awk '{print $1}' | grep -qx "strongswan-starter.service"; then
    systemctl enable strongswan-starter >/dev/null 2>&1 || true
    systemctl restart strongswan-starter
  elif systemctl list-unit-files | awk '{print $1}' | grep -qx "strongswan.service"; then
    systemctl enable strongswan >/dev/null 2>&1 || true
    systemctl restart strongswan
  fi

  systemctl restart ct-vip
  systemctl restart xray-socks
  systemctl restart xl2tpd
  systemctl restart ct-l2tp-fw
}

show_current() {
  load_current
  echo ""
  echo "当前配置："
  echo "SOCKS 用户: ${CUR_SOCKS_USER}"
  echo "SOCKS 密码: ${CUR_SOCKS_PASS}"
  echo "SOCKS 端口: ${CUR_SOCKS_PORT}"
  echo "L2TP 密码: ${CUR_L2TP_PASS}"
  echo "L2TP PSK: ${CUR_PSK}"
  echo ""
}

while true; do
  show_current
  echo "========== wawacloud 管理菜单 =========="
  echo "1) 修改 SOCKS 账号/密码/端口"
  echo "2) 修改 L2TP 统一密码"
  echo "3) 修改 L2TP PSK 密钥"
  echo "4) 一键修改全部（SOCKS+L2TP+PSK）"
  echo "5) 仅重启全部服务"
  echo "0) 退出"
  read -r -p "请选择: " choice

  case "$choice" in
    1)
      read -r -p "输入新 SOCKS 用户名: " n_user
      read -r -p "输入新 SOCKS 密码: " n_pass
      read -r -p "输入新 SOCKS 端口: " n_port
      validate_port "$n_port"
      write_xray_config "$n_user" "$n_pass" "$n_port"
      restart_stack
      echo "✅ SOCKS 配置已更新并生效"
      ;;
    2)
      read -r -p "输入新 L2TP 密码: " n_l2tp_pass
      update_l2tp_pass "$n_l2tp_pass"
      restart_stack
      echo "✅ L2TP 密码已更新并生效"
      ;;
    3)
      read -r -p "输入新 L2TP PSK: " n_psk
      update_psk "$n_psk"
      restart_stack
      echo "✅ L2TP PSK 已更新并生效"
      ;;
    4)
      read -r -p "输入新 SOCKS 用户名: " n_user
      read -r -p "输入新 SOCKS 密码: " n_pass
      read -r -p "输入新 SOCKS 端口: " n_port
      read -r -p "输入新 L2TP 密码: " n_l2tp_pass
      read -r -p "输入新 L2TP PSK: " n_psk
      validate_port "$n_port"
      write_xray_config "$n_user" "$n_pass" "$n_port"
      update_l2tp_pass "$n_l2tp_pass"
      update_psk "$n_psk"
      restart_stack
      echo "✅ 全部配置已更新并生效"
      ;;
    5)
      restart_stack
      echo "✅ 服务已重启"
      ;;
    0)
      exit 0
      ;;
    *)
      echo "无效选项"
      ;;
  esac
done
EOF
chmod +x /usr/local/bin/wawacloud

# 开机自愈：确保续费/重启后关键服务自动恢复
cat >/usr/local/sbin/wawacloud-ensure.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

systemctl start ct-vip >/dev/null 2>&1 || true

if systemctl list-unit-files | awk '{print $1}' | grep -qx "strongswan-starter.service"; then
  systemctl start strongswan-starter >/dev/null 2>&1 || true
elif systemctl list-unit-files | awk '{print $1}' | grep -qx "strongswan.service"; then
  systemctl start strongswan >/dev/null 2>&1 || true
fi

systemctl start xl2tpd >/dev/null 2>&1 || true
systemctl start ct-l2tp-fw >/dev/null 2>&1 || true
systemctl restart xray-socks >/dev/null 2>&1 || true
EOF
chmod +x /usr/local/sbin/wawacloud-ensure.sh

cat >/etc/systemd/system/wawacloud-ensure.service <<'EOF'
[Unit]
Description=Ensure Wawacloud Proxy/VPN Stack
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/wawacloud-ensure.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now wawacloud-ensure

# 绑定指定源IP请求公网探测接口，获取该出口的公网IP
query_public_ip() {
  probe_public_ip_common "$1"
}

echo "🔍 [8/8] 正在生成 $(basename "$OUTPUT_FILE") ..."
umask 077
: > "$OUTPUT_FILE"

declare -A PUB_IP_MAP
ORDERED_IPS=("${ALL_IPS[@]}")
SUCCESS_IPS=()
MAIN_SERVER_IP=""

# 先探测每个内网源 IP 对应的公网出口 IP
for int_ip in "${ORDERED_IPS[@]}"; do
  pub_ip="$(query_public_ip "$int_ip" || true)"
  if [[ -z "$pub_ip" && "$int_ip" == "$MAIN_IP" ]]; then
    pub_ip="$(probe_public_ip_default || true)"
    if [[ -n "$pub_ip" ]]; then
      echo "ℹ️ 主IP $int_ip 绑定源探测失败，已使用默认出口公网 $pub_ip"
    fi
  fi
  if [[ -n "$pub_ip" ]]; then
    echo "✅ 检测: 内网 $int_ip -> 公网 $pub_ip"
    PUB_IP_MAP["$int_ip"]="$pub_ip"
    SUCCESS_IPS+=("$int_ip")
    if [[ "$int_ip" == "$MAIN_IP" ]]; then
      MAIN_SERVER_IP="$pub_ip"
    fi
  else
    echo "❌ 内网 $int_ip 获取公网IP失败"
    PUB_IP_MAP["$int_ip"]="获取失败"
  fi
done

if [[ "${#SUCCESS_IPS[@]}" -eq 0 ]]; then
  echo "没有任何内网 IP 成功获取公网 IP，无法生成 L2TP/Socks5 结果。"
  exit 1
fi

# 兜底入口 IP：主 IP 探测失败时，取第一个可用公网 IP
if [[ -z "$MAIN_SERVER_IP" ]]; then
  for k in "${SUCCESS_IPS[@]}"; do
    if [[ "${PUB_IP_MAP[$k]}" != "获取失败" && -n "${PUB_IP_MAP[$k]}" ]]; then
      MAIN_SERVER_IP="${PUB_IP_MAP[$k]}"
      break
    fi
  done
fi
if [[ -z "$MAIN_SERVER_IP" ]]; then
  MAIN_SERVER_IP="获取失败"
fi

{
  echo ""
  echo "==================== SOCKS5 信息 ===================="
  echo ""
  echo "格式: IP/端口/账号/密码"
  echo ""

  for int_ip in "${SUCCESS_IPS[@]}"; do
    pub_ip="${PUB_IP_MAP[$int_ip]}"
    echo "${pub_ip}/${SOCKS_PORT}/${SOCKS_USER}/${SOCKS_PASS}"
  done

  echo ""
  echo ""
  echo "===================== L2TP 信息 ====================="
  echo ""
  echo "格式: 入口IP/账号/密码/密钥/出口IP"
  echo ""

  count=1
  for int_ip in "${ORDERED_IPS[@]}"; do
    pub_ip="${PUB_IP_MAP[$int_ip]}"
    if [[ "$pub_ip" == "获取失败" || -z "$pub_ip" ]]; then
      ((count++))
      continue
    fi
    echo "${MAIN_SERVER_IP}/user${count}/${L2TP_PASS}/${L2TP_PSK}/${pub_ip}"
    ((count++))
  done

  echo ""
  echo ""
  echo "======================================================"
  echo ""
  echo "免责声明：仅用于合法合规的网络技术交流用途。"
  echo "使用者需自行承担一切行为责任。"
  echo ""
  echo "+--------------------------------------------------+"
  echo "| 官方交流群 / 联系方式"
  echo "+--------------------------------------------------+"
  echo "| 天翼云4.5折交流群：159500025"
  echo "| 华为云8.8折交流群：916383784"
  echo "| 火山引擎交流群：1051985214"
  echo "+--------------------------------------------------+"
  echo "| 技术微信：lywwyjs"
  echo "+--------------------------------------------------+"
  echo ""
} >> "$OUTPUT_FILE"

echo "✅✅✅ 全部完成！"
echo "[√] 结果已保存到: $OUTPUT_FILE"
echo "[√] VIP 检测文件: $VIP_DIAG_FILE"
echo "[√] L2TP 映射文件: $L2TP_USER_MAP_FILE"
echo "[√] 管理菜单已安装，输入 'wawacloud' 即可修改账号/密码/密钥/端口"
cat "$OUTPUT_FILE"
