#!/bin/bash
# =============================================================
# Debian 12 L2TP/IPsec 多出口终版（华为云：单网卡 + 4 辅助出口，共 user1~user5）
# 组件：strongSwan + xl2tpd + ppp + iptables
# 出口策略：
#   user1 -> 主出口（MASQUERADE）
#   user2~user5 -> 按 /root/ip.txt 前4行（VLAN_ID MAC IP）独立出口（VLAN + SNAT + PBR）
# 自恢复：systemd wawa-l2tp-restore.service
# 一键修改：命令 wawa（进入界面改 VPN 密码 / PSK，并自动重启生效）
# 结尾输出：完整输出 user1~user5（含对应出口公网IP）
# =============================================================

set -e
trap 'echo "[ERROR] 行号 ${LINENO} 出错，脚本中止"; exit 1' ERR

# ----------------- 可改参数区 -----------------
CONFIG_FILE="/root/ip.txt"      # VLAN_ID MAC IP（前4行用于 user2~user5）
PARENT_IF="eth0"                # 母接口（华为云一般 eth0）
GATEWAY_IP="192.168.0.1"        # 网关（不一致请改）
LAN_PREFIX_LEN="24"             # 子网掩码（/24 常见）
VPN_POOL_START="172.30.0.10"    # 分配起始
VPN_POOL_END="172.30.0.50"      # 分配结束
VPN_LOCAL_IP="172.30.0.1"       # LNS 本地地址
USER_FIXED_IPS=("172.30.0.10" "172.30.0.11" "172.30.0.12" "172.30.0.13" "172.30.0.14")

WAWA_CMD="/usr/local/bin/wawa"
RESTORE_SCRIPT="/usr/local/bin/wawa-l2tp-restore.sh"
RESTORE_SERVICE="/etc/systemd/system/wawa-l2tp-restore.service"

# ----------------- 基础检查 -----------------
if [ "$(id -u)" -ne 0 ]; then
  echo "错误：请用 root 运行。"
  exit 1
fi

if [ ! -f "${CONFIG_FILE}" ]; then
  echo "错误：未找到 ${CONFIG_FILE}，请准备 VLAN_ID MAC IP 三列（前4行用于 user2~user5）。"
  exit 1
fi

ip link show "${PARENT_IF}" >/dev/null 2>&1 || { echo "错误：未找到母接口 ${PARENT_IF}"; exit 1; }

# ----------------- 安装依赖（Debian 12）-----------------
echo "=== 1) 安装依赖（Debian 12） ==="
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get install -y \
  strongswan strongswan-pki \
  xl2tpd ppp \
  iproute2 iptables iptables-persistent \
  vlan curl

# ----------------- 内核与 sysctl -----------------
echo "=== 2) 内核参数与模块 ==="
modprobe 8021q || true
cat >/etc/modules-load.d/8021q.conf <<EOF
8021q
EOF

cat >/etc/sysctl.d/99-wawa-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.${PARENT_IF}.rp_filter = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
EOF
sysctl --system

# ----------------- 输入 PSK 与密码（首次部署用） -----------------
echo "=== 3) 输入 PSK 与 VPN 密码（首次部署） ==="
read -r -p "请输入 IPSec PSK（默认 wawa）: " PSK
PSK="${PSK:-wawa}"

while true; do
  read -r -p "请输入 VPN 登录密码（user1~user5 共用）: " VPN_PASS
  [ -n "${VPN_PASS}" ] && break
  echo "密码不能为空！"
done

# ----------------- strongSwan 配置 -----------------
echo "=== 4) 配置 strongSwan（IPsec） ==="
cat >/etc/ipsec.conf <<EOF
config setup
  uniqueids=no

conn l2tp-psk
  keyexchange=ikev1
  authby=psk
  ike=aes128-sha1-modp1024,3des-sha1-modp1024!
  esp=aes128-sha1,3des-sha1!
  ikelifetime=8h
  keylife=1h
  rekey=no
  type=transport
  left=%defaultroute
  leftprotoport=17/1701
  right=%any
  rightprotoport=17/%any
  auto=add
EOF

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

# ----------------- xl2tpd 配置 -----------------
echo "=== 5) 配置 xl2tpd ==="
mkdir -p /etc/xl2tpd
cat >/etc/xl2tpd/xl2tpd.conf <<EOF
[global]
ipsec saref = yes

[lns default]
ip range = ${VPN_POOL_START}-${VPN_POOL_END}
local ip = ${VPN_LOCAL_IP}
require chap = yes
refuse pap = yes
require authentication = yes
pppoptfile = /etc/ppp/options.xl2tpd
length bit = yes
EOF

# ----------------- ppp 配置 -----------------
echo "=== 6) 配置 PPP ==="
cat >/etc/ppp/options.xl2tpd <<EOF
require-mschap-v2
ms-dns 119.29.29.29
ms-dns 223.5.5.5
asyncmap 0
auth
crtscts
lock
hide-password
modem
name xl2tpd
proxyarp
lcp-echo-interval 30
lcp-echo-failure 4
mtu 1400
mru 1400
EOF

# ----------------- chap-secrets（固定分配 user1~user5） -----------------
echo "=== 7) 写入 chap-secrets（固定分配IP） ==="
cat >/etc/ppp/chap-secrets <<EOF
"user1" xl2tpd "${VPN_PASS}" ${USER_FIXED_IPS[0]}
"user2" xl2tpd "${VPN_PASS}" ${USER_FIXED_IPS[1]}
"user3" xl2tpd "${VPN_PASS}" ${USER_FIXED_IPS[2]}
"user4" xl2tpd "${VPN_PASS}" ${USER_FIXED_IPS[3]}
"user5" xl2tpd "${VPN_PASS}" ${USER_FIXED_IPS[4]}
EOF
chmod 600 /etc/ppp/chap-secrets

# ----------------- 自恢复脚本（VLAN + PBR + iptables） -----------------
echo "=== 8) 生成自恢复脚本 ${RESTORE_SCRIPT} ==="
cat >"${RESTORE_SCRIPT}" <<EOF
#!/bin/bash
# 我是代码注释：wawa-l2tp-restore - 重建 VLAN + PBR + iptables（幂等）
set -e

CONFIG_FILE="${CONFIG_FILE}"
PARENT_IF="${PARENT_IF}"
GATEWAY_IP="${GATEWAY_IP}"
LAN_PREFIX_LEN="${LAN_PREFIX_LEN}"
PPP_IPS=("172.30.0.11" "172.30.0.12" "172.30.0.13" "172.30.0.14")

read_iptxt_4() {
  head -n 4 "\${CONFIG_FILE}" | sed 's/\\r$//' | while read -r VLAN_ID MAC IP; do
    [ -z "\${VLAN_ID}" ] && continue
    echo "\${VLAN_ID} \${MAC} \${IP}"
  done
}

rebuild_vlan() {
  read_iptxt_4 | while read -r VLAN_ID MAC IP; do
    IFNAME="\${PARENT_IF}.\${VLAN_ID}"
    ip link show "\${IFNAME}" >/dev/null 2>&1 && ip link delete "\${IFNAME}" type vlan || true
    ip link add link "\${PARENT_IF}" name "\${IFNAME}" type vlan id "\${VLAN_ID}"
    ip addr add "\${IP}/\${LAN_PREFIX_LEN}" dev "\${IFNAME}"
    ip link set dev "\${IFNAME}" address "\${MAC}" 2>/dev/null || true
    ip link set "\${IFNAME}" up
  done
}

rebuild_pbr() {
  for tid in 100 101 102 103; do
    ip route flush table "\${tid}" 2>/dev/null || true
  done

  for i in 0 1 2 3; do
    src="\${PPP_IPS[\$i]}"
    tid=\$((100+i))
    ip rule del from "\${src}/32" table "\${tid}" priority "\${tid}" 2>/dev/null || true
  done

  i=0
  read_iptxt_4 | while read -r VLAN_ID MAC IP; do
    [ "\${i}" -ge 4 ] && break
    IFNAME="\${PARENT_IF}.\${VLAN_ID}"
    SRC="\${PPP_IPS[\$i]}"
    TID=\$((100+i))
    ip rule add from "\${SRC}/32" table "\${TID}" priority "\${TID}"
    ip route add default via "\${GATEWAY_IP}" dev "\${IFNAME}" table "\${TID}"
    i=\$((i+1))
  done

  ip route flush cache || true
}

rebuild_iptables() {
  iptables -C INPUT -p udp --dport 500 -j ACCEPT 2>/dev/null || iptables -I INPUT -p udp --dport 500 -j ACCEPT
  iptables -C INPUT -p udp --dport 4500 -j ACCEPT 2>/dev/null || iptables -I INPUT -p udp --dport 4500 -j ACCEPT
  iptables -C INPUT -p udp --dport 1701 -j ACCEPT 2>/dev/null || iptables -I INPUT -p udp --dport 1701 -j ACCEPT

  iptables -P FORWARD ACCEPT
  iptables -C FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
  iptables -C FORWARD -s 172.30.0.0/24 -j ACCEPT 2>/dev/null || iptables -A FORWARD -s 172.30.0.0/24 -j ACCEPT

  iptables -t mangle -C FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu 2>/dev/null || \
    iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

  iptables -t nat -F POSTROUTING

  i=0
  read_iptxt_4 | while read -r VLAN_ID MAC IP; do
    [ "\${i}" -ge 4 ] && break
    iptables -t nat -A POSTROUTING -s "\${PPP_IPS[\$i]}/32" -j SNAT --to-source "\${IP}"
    i=\$((i+1))
  done

  iptables -t nat -A POSTROUTING -s 172.30.0.0/24 -j MASQUERADE
  netfilter-persistent save >/dev/null 2>&1 || true
}

main() {
  [ -f "\${CONFIG_FILE}" ] || exit 0
  rebuild_vlan
  rebuild_pbr
  rebuild_iptables
}
main
EOF
chmod +x "${RESTORE_SCRIPT}"

# ----------------- systemd 自恢复服务 -----------------
echo "=== 9) 写入 systemd 自恢复服务 ==="
cat >"${RESTORE_SERVICE}" <<EOF
[Unit]
Description=WawaCloud L2TP multi-exit restore (VLAN/PBR/iptables)
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=${RESTORE_SCRIPT}
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable wawa-l2tp-restore.service

# ----------------- 执行一次自恢复 -----------------
echo "=== 10) 执行一次自恢复（创建 VLAN/PBR/iptables） ==="
bash "${RESTORE_SCRIPT}"

# ----------------- 启动服务并自启 -----------------
echo "=== 11) 启动 strongSwan 与 xl2tpd ==="
systemctl enable --now strongswan-starter
systemctl restart strongswan-starter

systemctl enable --now xl2tpd
systemctl restart xl2tpd

# ----------------- 生成 wawa 命令：修改界面（改 PSK/密码） -----------------
echo "=== 12) 生成命令：wawa（修改 PSK/密码 界面） ==="
cat >"${WAWA_CMD}" <<'EOF'
#!/bin/bash
# 我是代码注释：wawa - 一键修改 L2TP：VPN 密码（user1~user5） + IPSec PSK，并重启生效
set -e

if [ "$(id -u)" -ne 0 ]; then
  echo "错误：请用 root 执行。"
  exit 1
fi

OLD_PSK="$(grep -Eo 'PSK ".*"' /etc/ipsec.secrets 2>/dev/null | head -n1 | sed 's/PSK "//;s/"$//' || true)"
OLD_PASS="$(awk 'NR==1{print $4}' /etc/ppp/chap-secrets 2>/dev/null | tr -d '"' || true)"

echo ""
echo "========== L2TP 一键修改界面 =========="
echo "当前 PSK      : ${OLD_PSK:-未知}"
echo "当前 VPN 密码 : ${OLD_PASS:-未知}"
echo "--------------------------------------"
echo "提示：直接回车表示保留不变"
echo ""

read -r -p "输入新的 PSK(回车保留): " NEW_PSK
read -r -p "输入新的 VPN 密码(回车保留): " NEW_PASS

if [ -n "${NEW_PSK}" ]; then
  cat >/etc/ipsec.secrets <<EOF2
%any %any : PSK "${NEW_PSK}"
EOF2
fi

if [ -n "${NEW_PASS}" ]; then
  cat >/etc/ppp/chap-secrets <<EOF2
"user1" xl2tpd "${NEW_PASS}" 172.30.0.10
"user2" xl2tpd "${NEW_PASS}" 172.30.0.11
"user3" xl2tpd "${NEW_PASS}" 172.30.0.12
"user4" xl2tpd "${NEW_PASS}" 172.30.0.13
"user5" xl2tpd "${NEW_PASS}" 172.30.0.14
EOF2
  chmod 600 /etc/ppp/chap-secrets
fi

systemctl restart strongswan-starter
systemctl restart xl2tpd

echo ""
echo "✅ 修改完成并已重启服务生效。"
EOF
chmod +x "${WAWA_CMD}"

# ----------------- 输出交付信息（完整：user1~user5） -----------------
echo ""
echo "=== 13) 输出交付信息（user1~user5） ==="

SERVER_PUBIP="$(curl -s --max-time 6 ifconfig.me || echo "获取失败")"

get_pub_by_src() {
  local src_ip="$1"
  local out ip4
  for url in \
    "http://whatismyip.akamai.com" \
    "https://api.ipify.org" \
    "https://ip.sb" \
    "https://ipv4.icanhazip.com"
  do
    out="$(curl -s --max-time 6 --connect-timeout 4 --interface "${src_ip}" "${url}" || true)"
    ip4="$(echo "${out}" | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -n1 || true)"
    [ -n "${ip4}" ] && { echo "${ip4}"; return 0; }
  done
  echo "获取失败"
  return 0
}

echo "服务器公网IP / 用户名 / 密码 / PSK / 对应出口公网IP"
echo "------------------------------------------------------"

# user1 走主出口
echo "${SERVER_PUBIP} / user1 / ${VPN_PASS} / ${PSK} / ${SERVER_PUBIP}"

# user2~user5：按 ip.txt 前4行对应出口
USER_INDEX=2
head -n 4 "${CONFIG_FILE}" | sed 's/\r$//' | while read -r VLAN_ID MAC IP; do
  [ -z "${VLAN_ID}" ] && continue
  [ -z "${MAC}" ] && continue
  [ -z "${IP}" ] && continue

  WAN_IP="$(get_pub_by_src "${IP}")"
  echo "${SERVER_PUBIP} / user${USER_INDEX} / ${VPN_PASS} / ${PSK} / ${WAN_IP}"

  USER_INDEX=$((USER_INDEX + 1))
done

echo ""
echo "常用命令："
echo "  systemctl status strongswan-starter xl2tpd"
echo "  systemctl status wawa-l2tp-restore.service"
echo "  ${RESTORE_SCRIPT}     # 手动重建 VLAN/PBR/iptables"
echo "  wawa                  # 一键修改 PSK/密码（界面）"
