#!/bin/bash
# ============================================================
#   OpenCloudOS 9 OpenVPN 主力稳定版（UDP 1194）
#   版本：OC9-MAIN-3.8
#   日期：2026-08-18
#   系统：OpenCloudOS 9 标准正式版专用（dnf包管理器）
#
#   【3.8新增 - 完全对齐3-17-2能连版本配置】
#   - 客户端auth SHA256→SHA512（与3-17-2一致）
#   - 移除客户端data-ciphers和cipher指令（让3.x客户端自动协商，与3-17-2一致）
#   - 移除客户端mssfix/tun-mtu/replay-window（与3-17-2一致，避免过度配置导致兼容性问题）
#   - 加ignore-unknown-option block-outside-dns（与3-17-2一致，防DNS泄漏→白屏）
#   - 服务端auth SHA256→SHA512，移除data-ciphers（与3-17-2服务端一致）
#   - 根因：之前加的data-ciphers/mssfix/replay-window等参数与OpenVPN 3.x不兼容
#
#   【3.7 - 彻底解决TLS握手失败（tls-auth→tls-crypt）】
#   - 改用tls-crypt替代tls-auth：不需要key-direction，OpenVPN 3.x完全兼容
#   - 根因：tls-auth+key-direction在OpenVPN 3.x客户端可能出现HMAC验证失败
#   - tls-crypt更现代：加密+HMAC双重保护，不需要direction，更简单可靠
#   - 移除key-direction 1：tls-crypt不需要此参数
#
#   【3.6 - 解决OpenVPN Connect 3.x客户端连不上（fragment不兼容）】
#   - 移除fragment 1200：3.x客户端不支持fragment指令，会导致连接失败
#   - 改用mssfix 1200：3.x兼容，控制OpenVPN包≤1200字节，替代fragment功能
#   - 客户端模板加mssfix 1200 + tun-mtu 1500：与服务端一致
#   - 根因：服务端有fragment 1200但客户端3.x不支持，分片包无法重组→握手卡住
#
#   【3.5新增 - 解决频繁掉线（实测：40分钟掉4-5次，每8-10分钟掉一次）】
#   - keepalive 10 60 → 10 180：超时阈值60→180秒，容忍跨运营商链路3分钟抖动
#     根因：辽宁联通→腾讯云UDP链路高峰期抖动>60秒，触发频繁重连
#   - reneg-sec 3600 → 0：禁用每小时密钥重协商，消除重协商时链路抖动导致的掉线
#     一对一内网场景安全性够用，稳定性优先
#
#   【3.4新增 - 解决断开后无法立即重连（抓包实证：TLS握手成功但客户端掉线后重连被拒）】
#   - duplicate-cn：允许同证书断开后立即重连，不用等服务端清死会话
#     抓包证据：TLS握手23:29:13完成→数据通道建立→客户端掉线→重连时服务端认为pc0仍在线→拒绝
#   - inactive 300→60：死会话清理从5分钟缩短到1分钟，加速IP回收
#
#   【3.3新增 - 抓包实证修复（Connection timeout/Packet ID replay）】
#   - fragment 1200：应用层分片，解决TLS握手1222字节大包被轻量云/运营商丢弃
#     抓包证据：服务端Out 1222字节×2 → 客户端只ACK未收全 → 服务端2/4/8/16秒指数退避重传 → 超时
#   - replay-window 1024 30：扩大重放窗口，解决UDP乱序导致的Packet ID replay error
#
#   【3.2新增 - 腾讯轻量云专属微调（生产级体检报告采纳）】
#   - mssfix 1420：腾讯轻量MTU=1500黄金值，比1400更匹配tun-mtu 1500
#   - fast-io：UDP高并发减少syscall，一对一稳定、多VM并发也稳
#   - explicit-exit-notify 1：UDP模式减少轻量云会话假死
#
#   【3.1新增 - 整合外部意见文件的安全加固】
#   - tls-crypt + ta.key：加密+HMAC防火墙，防DoS攻击和端口扫描（3.7升级）
#   - user/group nobody：启动后权限降级，安全加固
#   - tls-version-min 1.2：禁用弱TLS 1.0/1.1
#   - ifconfig-pool-persist：重连后IP稳定，不再漂移
#   - remote-cert-tls server：客户端校验服务端证书类型（与服务端对称）
#   - mute 20：日志降噪，重复消息只记一次
#
#   【意见文件优质内容整合】
#   - 腾讯自研原生系统，内核5.10+，原生BBR，UDP丢包率比CentOS低30%
#   - 主端口：UDP 1194（延迟低、吞吐流畅，8台虚拟机Pi Node不白屏）
#   - 核心优化：mssfix 1200（3.x兼容，替代fragment）→ 解决UDP大包分片白屏
#   - 死会话自动清理：keepalive 10 180 + inactive 60（1分钟空闲自动踢）
#   - max-clients 16（8台机留双倍余量，彻底根除占坑）
#   - 一机一证 + duplicate-cn（允许断开后立即重连）
#   - 完整内核优化：BBR + UDP缓冲区 + 网络队列
#   - firewalld原生支持 + masquerade地址伪装
#
#   【历史修复经验整合】
#   - 证书仅提取PEM格式（无文本描述，避免TLS解析失败）
#   - iptables幂等添加（绝不-F清空，避免SSH断线）
#   - 系统源装什么版本用什么版本（不折腾降版本，一份配置通吃）
#   - 防火墙规则顺序：ESTABLISHED → lo → 主力端口（避免阻断）
#   - 增大sndbuf/rcvbuf/txqueuelen（避免Bad packet length）
#   - AES-256-CBC + auth SHA512 加密（对齐3-17-2能连版本，不折腾GCM）
#   - auth-nocache + 一机一证
#   - 日志轮转7天 + reneg-sec 0禁用密钥重协商（稳定性优先）
# ============================================================

set -e

# 颜色
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'

# ============================================================
# 参数（8台机方案：max-clients 16，端口独立）
# ============================================================
CLIENT_NAME="${1:-pc0}"
VPN_PORT="1194"
PROTOCOL="udp"
NETWORK="10.8.0.0"
SERVER_CN="vpn-server"
DNS1="119.29.29.29"
DNS2="223.5.5.5"
MAX_CLIENTS="16"

# ============================================================
# 欢迎信息
# ============================================================
echo -e "${GREEN}==============================================${NC}"
echo -e "${GREEN}  OpenCloudOS 9 OpenVPN 主力稳定版${NC}"
echo -e "${GREEN}  vOC9-MAIN-3.8 (UDP 1194 · 腾讯轻量专版)${NC}"
echo -e "${GREEN}==============================================${NC}"
echo -e "${YELLOW}部署参数:${NC}"
echo -e "  客户端名:  ${GREEN}$CLIENT_NAME${NC}"
echo -e "  协议:      ${GREEN}UDP（延迟低，Pi Node不白屏）${NC}"
echo -e "  端口:      ${GREEN}1194${NC}"
echo -e "  最大连接:  ${GREEN}$MAX_CLIENTS（8台机留双倍余量，防占坑）${NC}"
echo -e "  加密:      ${GREEN}AES-256-CBC + SHA512${NC}"
echo -e "  TLS防护:   ${GREEN}tls-crypt加密防火墙（防DoS，3.x兼容）${NC}"
echo -e "  内核:      ${GREEN}BBR加速 + UDP缓冲区优化${NC}"
echo -e "  死会话:    ${GREEN}1分钟空闲自动清理${NC}"

if [ "$(id -u)" != "0" ]; then
    echo -e "${RED}错误：必须以root用户执行${NC}"
    exit 1
fi

# ============================================================
# 0. 清理旧环境（幂等，不破坏现有连接）
# ============================================================
echo -e "\n${YELLOW}[0/12] 清理旧环境...${NC}"

systemctl stop openvpn-server@server 2>/dev/null || true
systemctl stop openvpn@server 2>/dev/null || true
pkill -f "openvpn.*server" 2>/dev/null || true
sleep 1

# 只删配置，不删防火墙规则（避免SSH断）
rm -rf /etc/openvpn/server /etc/openvpn/client /etc/openvpn/easy-rsa/pki 2>/dev/null || true
rm -f /etc/systemd/system/openvpn-server@*.service 2>/dev/null || true
rm -f /etc/systemd/system/openvpn@*.service 2>/dev/null || true
rm -f /root/*.ovpn 2>/dev/null || true
systemctl daemon-reload 2>/dev/null || true

echo -e "  ${GREEN}✓ 旧环境已清理${NC}"

# ============================================================
# 1. 系统检测 + OpenCloudOS专属包管理器
# ============================================================
echo -e "\n${YELLOW}[1/12] 系统检测...${NC}"

if [ -f /etc/opencloudos-release ]; then
    OS_VERSION=$(cat /etc/opencloudos-release 2>/dev/null || cat /etc/os-release | grep PRETTY_NAME | head -1)
    echo -e "  系统: $OS_VERSION"
elif [ -f /etc/os-release ]; then
    OS_VERSION=$(grep PRETTY_NAME /etc/os-release | head -1)
    echo -e "  系统: $OS_VERSION"
fi

# OpenCloudOS 9 用 dnf
if command -v dnf &> /dev/null; then
    PKG_MGR="dnf"
elif command -v yum &> /dev/null; then
    PKG_MGR="yum"
else
    echo -e "${RED}✗ 未找到 dnf 或 yum${NC}"
    exit 1
fi
echo -e "  包管理器: $PKG_MGR (OpenCloudOS专属)"

# 公网IP
echo -e "  ${CYAN}检测公网IP...${NC}"
PUBLIC_IP=""
for source in \
    "https://api.ipify.org" \
    "https://ifconfig.me" \
    "https://ipinfo.io/ip" \
    "https://ip.sb" \
    "https://checkip.amazonaws.com" \
    "https://icanhazip.com"; do
    PUBLIC_IP=$(curl -s --connect-timeout 5 "$source" 2>/dev/null | tr -d '[:space:]')
    if echo "$PUBLIC_IP" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'; then
        break
    fi
done
if ! echo "$PUBLIC_IP" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'; then
    PUBLIC_IP=$(curl -s --connect-timeout 3 http://169.254.0.23/latest/meta-data/public-ipv4 2>/dev/null | tr -d '[:space:]')
fi
if ! echo "$PUBLIC_IP" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'; then
    PUBLIC_IP=$(hostname -I 2>/dev/null | awk '{print $1}')
fi
if ! echo "$PUBLIC_IP" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'; then
    read -p "  请输入公网IP: " PUBLIC_IP
fi
echo -e "  公网IP:   ${GREEN}$PUBLIC_IP${NC}"

# 网络接口
IFACE=$(ip route show default 2>/dev/null | awk '{print $5}' | head -1)
if [ -z "$IFACE" ] || [ "$IFACE" = "lo" ]; then
    for test_iface in eth0 ens33 ens160 enp0s3 enp1s0 ens192 eth1; do
        if ip link show "$test_iface" >/dev/null 2>&1; then
            IFACE="$test_iface"
            break
        fi
    done
fi
[ -z "$IFACE" ] || [ "$IFACE" = "lo" ] && IFACE="eth0"
echo -e "  网络接口: ${GREEN}$IFACE${NC}"

# ============================================================
# 2. 安装软件包（系统源装什么用什么，不折腾版本）
# ============================================================
echo -e "\n${YELLOW}[2/12] 安装软件包...${NC}"

$PKG_MGR install -y epel-release 2>/dev/null || true
$PKG_MGR install -y curl wget net-tools iptables iptables-services openssl openssh-server iproute firewalld 2>/dev/null || true

if ! $PKG_MGR install -y openvpn 2>/dev/null; then
    echo -e "${YELLOW}  ⚠ OpenVPN未找到，尝试启用CRB/Plus源...${NC}"
    $PKG_MGR config-manager --set-enabled crb 2>/dev/null || true
    $PKG_MGR config-manager --set-enabled plus 2>/dev/null || true
    $PKG_MGR update -y 2>/dev/null || true
    $PKG_MGR install -y openvpn || {
        echo -e "${RED}✗ OpenVPN安装失败${NC}"
        exit 1
    }
fi

OVPN_VERSION=$(openvpn --version 2>/dev/null | head -1 | grep -oP '\d+\.\d+\.\d+' || echo "2.4")
echo -e "  OpenVPN:   v${OVPN_VERSION}"

# EasyRSA
mkdir -p /etc/openvpn/easy-rsa
if [ -f /usr/share/easy-rsa/easyrsa ]; then
    cp -r /usr/share/easy-rsa/* /etc/openvpn/easy-rsa/
    echo -e "  EasyRSA:   系统包"
else
    $PKG_MGR install -y easy-rsa 2>/dev/null || true
    if [ -f /usr/share/easy-rsa/easyrsa ]; then
        cp -r /usr/share/easy-rsa/* /etc/openvpn/easy-rsa/
        echo -e "  EasyRSA:   EPEL包"
    else
        echo -e "  ${CYAN}下载EasyRSA 3.1.2...${NC}"
        cd /tmp
        wget -q --no-check-certificate https://github.com/OpenVPN/easy-rsa/releases/download/v3.1.2/EasyRSA-3.1.2.tgz
        tar -xzf EasyRSA-3.1.2.tgz
        cp -r EasyRSA-3.1.2/* /etc/openvpn/easy-rsa/
        cd /root
        echo -e "  EasyRSA:   GitHub下载"
    fi
fi
chmod +x /etc/openvpn/easy-rsa/easyrsa
EASYRSA_CMD="/etc/openvpn/easy-rsa/easyrsa"
[ ! -f "$EASYRSA_CMD" ] && { echo -e "${RED}✗ EasyRSA安装失败${NC}"; exit 1; }

# ============================================================
# 3. SELinux处理
# ============================================================
echo -e "\n${YELLOW}[3/12] 配置SELinux...${NC}"
if command -v getenforce &> /dev/null; then
    SELINUX_STATUS=$(getenforce 2>/dev/null)
    if [ "$SELINUX_STATUS" = "Enforcing" ]; then
        setenforce 0 2>/dev/null || true
        sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config 2>/dev/null || true
        echo -e "  ${GREEN}✓ SELinux设为Permissive${NC}"
    else
        echo -e "  ${GREEN}✓ SELinux状态: $SELINUX_STATUS${NC}"
    fi
else
    echo -e "  ${GREEN}✓ SELinux未安装${NC}"
fi

# ============================================================
# 4. 内核网络优化（OpenCloudOS 9专属：BBR + UDP缓冲区）
# ============================================================
echo -e "\n${YELLOW}[4/12] 内核网络优化（BBR + UDP防丢包）...${NC}"

# 先去重，再追加（幂等）
sed -i '/^net.ipv4.ip_forward/d; /^net.ipv4.ip_local_port_range/d; /^net.core.rmem_max/d; /^net.core.wmem_max/d; /^net.ipv4.udp_mem/d; /^net.core.netdev_max_backlog/d; /^net.core.default_qdisc/d; /^net.ipv4.tcp_congestion_control/d; /^net.ipv4.conf.all.rp_filter/d; /^net.ipv4.conf.all.accept_redirects/d' /etc/sysctl.conf 2>/dev/null || true

cat >> /etc/sysctl.conf << 'SYSCTLEOF'
# === OpenVPN + 8台Pi Node 专属优化 ===
# 基础转发
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.all.accept_redirects = 0
# UDP缓冲区优化（解决多机并发丢包）
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
net.ipv4.udp_mem = 25600 51200 102400
# 网络队列优化
net.core.netdev_max_backlog = 5000
# 端口范围
net.ipv4.ip_local_port_range = 1024 65535
# BBR拥塞控制（OpenCloudOS 9内核5.10+原生支持）
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
SYSCTLEOF

sysctl -p > /dev/null 2>&1

if [ "$(sysctl net.ipv4.ip_forward 2>/dev/null | awk '{print $3}')" = "1" ]; then
    echo -e "  ${GREEN}✓ IP转发已开启${NC}"
else
    echo -e "${RED}✗ IP转发开启失败${NC}"
    exit 1
fi

BBR_STATUS=$(sysctl net.ipv4.tcp_congestion_control 2>/dev/null | awk '{print $3}')
echo -e "  ${GREEN}✓ BBR拥塞控制: $BBR_STATUS${NC}"
echo -e "  ${GREEN}✓ UDP缓冲区已优化（64MB）${NC}"
echo -e "  ${GREEN}✓ 端口范围: 1024-65535${NC}"

# ============================================================
# 5. 生成证书（一机一证，不强制CN）
# ============================================================
echo -e "\n${YELLOW}[5/12] 生成证书和密钥（一机一证）...${NC}"

mkdir -p /etc/openvpn/server /etc/openvpn/client
cd /etc/openvpn/easy-rsa
export EASYRSA_BATCH=1

cat > vars << VARS
set_var EASYRSA_BATCH 1
set_var EASYRSA_REQ_COUNTRY "CN"
set_var EASYRSA_REQ_PROVINCE "Beijing"
set_var EASYRSA_REQ_CITY "Beijing"
set_var EASYRSA_REQ_ORG "PiNode"
set_var EASYRSA_KEY_SIZE 2048
set_var EASYRSA_ALGO rsa
set_var EASYRSA_CA_EXPIRE 3650
set_var EASYRSA_CERT_EXPIRE 3650
set_var EASYRSA_DIGEST "sha512"
VARS
source vars 2>/dev/null || true

echo -e "  ${CYAN}生成CA证书...${NC}"
yes | $EASYRSA_CMD init-pki 2>&1 || { echo -e "${RED}✗ init-pki失败${NC}"; exit 1; }
yes | $EASYRSA_CMD --batch build-ca nopass 2>&1 || { echo -e "${RED}✗ build-ca失败${NC}"; exit 1; }

echo -e "  ${CYAN}生成服务器证书 [CN=$SERVER_CN]...${NC}"
yes | $EASYRSA_CMD --batch gen-req "$SERVER_CN" nopass 2>&1 || { echo -e "${RED}✗ gen-req失败${NC}"; exit 1; }
yes | $EASYRSA_CMD --batch sign-req server "$SERVER_CN" 2>&1 || { echo -e "${RED}✗ sign-req失败${NC}"; exit 1; }

echo -e "  ${CYAN}生成DH参数（2048位）...${NC}"
openssl dhparam -out pki/dh.pem 2048 2>/dev/null || {
    yes | $EASYRSA_CMD --batch gen-dh 2>&1 || { echo -e "${RED}✗ DH参数失败${NC}"; exit 1; }
}

echo -e "  ${CYAN}生成客户端证书 [CN=$CLIENT_NAME]（一机一证）...${NC}"
yes | $EASYRSA_CMD --batch gen-req "$CLIENT_NAME" nopass 2>&1 || { echo -e "${RED}✗ gen-req失败${NC}"; exit 1; }
yes | $EASYRSA_CMD --batch sign-req client "$CLIENT_NAME" 2>&1 || { echo -e "${RED}✗ sign-req失败${NC}"; exit 1; }

cp pki/ca.crt pki/dh.pem pki/issued/$SERVER_CN.crt pki/private/$SERVER_CN.key /etc/openvpn/server/
cp pki/ca.crt pki/issued/$CLIENT_NAME.crt pki/private/$CLIENT_NAME.key /etc/openvpn/client/

# 生成ta.key（tls-crypt：加密+HMAC防火墙，防DoS攻击和端口扫描）
# 使用tls-crypt替代tls-auth：不需要key-direction，OpenVPN 3.x完全兼容
# 兼容OpenVPN 2.4（--genkey --secret）和2.5+（--genkey secret）两种语法
echo -e "  ${CYAN}生成ta.key（tls-crypt加密防火墙）...${NC}"
if ! openvpn --genkey secret /etc/openvpn/server/ta.key 2>/dev/null; then
    openvpn --genkey --secret /etc/openvpn/server/ta.key || { echo -e "${RED}✗ ta.key生成失败${NC}"; exit 1; }
fi
cp /etc/openvpn/server/ta.key /etc/openvpn/client/ta.key
chmod 600 /etc/openvpn/server/ta.key /etc/openvpn/client/ta.key
echo -e "  ${GREEN}✓ ta.key已生成（tls-crypt，无需key-direction）${NC}"

CA_SUB=$(openssl x509 -in pki/ca.crt -noout -subject 2>/dev/null)
SRV_SUB=$(openssl x509 -in pki/issued/$SERVER_CN.crt -noout -subject 2>/dev/null)
CLI_SUB=$(openssl x509 -in pki/issued/$CLIENT_NAME.crt -noout -subject 2>/dev/null)
echo -e "  ${GREEN}✓ CA:      $CA_SUB${NC}"
echo -e "  ${GREEN}✓ 服务器:  $SRV_SUB${NC}"
echo -e "  ${GREEN}✓ 客户端:  $CLI_SUB${NC}"
echo -e "  ${GREEN}✓ 一机一证 + duplicate-cn（允许断开后立即重连，topology subnet自动分配新IP）${NC}"

# ============================================================
# 6. 生成服务器配置（UDP 1194 + 白屏修复）—— 一份配置，简单直接
# ============================================================
echo -e "\n${YELLOW}[6/12] 生成服务器配置（UDP 1194 + Pi白屏修复）...${NC}"

cat > /etc/openvpn/server/server.conf << SERVEREOF
# === OpenCloudOS 9 主力版 - UDP 1194 ===
port $VPN_PORT
proto $PROTOCOL
dev tun

ca /etc/openvpn/server/ca.crt
cert /etc/openvpn/server/$SERVER_CN.crt
key /etc/openvpn/server/$SERVER_CN.key
dh /etc/openvpn/server/dh.pem
tls-crypt /etc/openvpn/server/ta.key

topology subnet
server $NETWORK 255.255.255.0
ifconfig-pool-persist /etc/openvpn/server/ipp.txt

# 白屏修复（mssfix 1200：控制OpenVPN包≤1200字节，避免运营商丢大UDP包）
# 注意：原fragment 1200已移除，因为OpenVPN Connect 3.x客户端不支持fragment指令
# mssfix在3.x兼容，间接控制TLS握手包大小，替代fragment功能
mssfix 1200
tun-mtu 1500
txqueuelen 1000
sndbuf 524288
rcvbuf 524288
push "sndbuf 524288"
push "rcvbuf 524288"
# UDP高并发减少syscall，8台VM并发更稳（OpenVPN 2.5+安全增强，不影响旧版）
fast-io
# 扩大重放窗口：解决轻量云UDP乱序导致的Packet ID replay error
# 默认64太小，扩到1024容忍30秒内的乱序包
replay-window 1024 30

# 死会话清理 + 抗抖动保活
# ping 10秒保活NAT不变；超时60→180秒：容忍跨运营商链路3分钟抖动不触发重连
# 实测：辽宁联通→腾讯云UDP链路，60秒超时40分钟掉4-5次，180秒彻底根治
keepalive 10 180
# 5分钟→1分钟：加速死会话回收，断开后重连不等5分钟
inactive 60
# 禁用密钥重协商：reneg-sec 3600每小时重协商时链路抖动会直接失败掉线
# 一对一内网场景安全性够用，稳定性优先
reneg-sec 0

max-clients $MAX_CLIENTS
# 允许同证书断开后立即重连（解决5分钟内重连被服务端拒绝的问题）
# topology subnet模式下重连会自动分配新IP，旧IP在inactive 60后回收，无冲突
duplicate-cn

# 加密（对齐之前好用的3-17-2版本：SHA512 + 不指定data-ciphers让客户端自动协商）
cipher AES-256-CBC
auth SHA512

# 客户端上网
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS $DNS1"
push "dhcp-option DNS $DNS2"

# 安全
verify-client-cert require
remote-cert-tls client
tls-version-min 1.2
user nobody
group nobody
persist-key
persist-tun

# 日志
status /etc/openvpn/server/status.log
log-append /etc/openvpn/server/openvpn.log
verb 3
mute 20
# UDP模式减少轻量云会话假死：服务端主动通知客户端连接关闭
explicit-exit-notify 1
SERVEREOF

echo -e "  ${GREEN}✓ 服务器配置完成${NC}"

# ============================================================
# 7. 生成客户端配置（证书纯PEM，无文本描述）
# ============================================================
echo -e "\n${YELLOW}[7/12] 生成客户端配置（纯PEM证书，无文本描述）...${NC}"

# 关键修复：只提取PEM格式证书，去掉Certificate: Data:等文本描述
# （混合内容会导致TLS握手直接失败）
CA_CRT=$(sed -n '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' /etc/openvpn/client/ca.crt)
CLI_CRT=$(sed -n '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' /etc/openvpn/client/$CLIENT_NAME.crt)
CLI_KEY=$(sed -n '/-----BEGIN PRIVATE KEY-----/,/-----END PRIVATE KEY-----/p' /etc/openvpn/client/$CLIENT_NAME.key)
TA_KEY=$(sed -n '/-----BEGIN OpenVPN Static key/,/-----END OpenVPN Static key/p' /etc/openvpn/client/ta.key)

cat > /etc/openvpn/client/$CLIENT_NAME.ovpn << CLIENTEOF
client
dev tun
proto $PROTOCOL
remote $PUBLIC_IP $VPN_PORT
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
auth SHA512
ignore-unknown-option block-outside-dns
verb 3

<cert>
$CLI_CRT
</cert>
<key>
$CLI_KEY
</key>
<ca>
$CA_CRT
</ca>
<tls-crypt>
$TA_KEY
</tls-crypt>
CLIENTEOF

cp /etc/openvpn/client/$CLIENT_NAME.ovpn /root/$CLIENT_NAME.ovpn

OVPN_SIZE=$(wc -c < /root/$CLIENT_NAME.ovpn)
if grep -q "BEGIN CERTIFICATE" /root/$CLIENT_NAME.ovpn && \
   grep -q "BEGIN PRIVATE KEY" /root/$CLIENT_NAME.ovpn && \
   grep -q "BEGIN OpenVPN Static key" /root/$CLIENT_NAME.ovpn; then
    echo -e "  ${GREEN}✓ OVPN文件完整（CA+证书+私钥+ta.key）${NC}"
    echo -e "  ${CYAN}  文件大小: $OVPN_SIZE 字节${NC}"
else
    echo -e "${RED}✗ OVPN文件内容不完整${NC}"
    exit 1
fi

# ============================================================
# 8. 日志轮转（防止日志占满磁盘）
# ============================================================
echo -e "\n${YELLOW}[8/12] 日志轮转配置...${NC}"
cat > /etc/logrotate.d/openvpn << 'LOGROTATEEOF'
/etc/openvpn/server/openvpn.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
}
LOGROTATEEOF
echo -e "  ${GREEN}✓ 日志轮转：每天轮转，保留7天${NC}"

# ============================================================
# 9. 防火墙（OpenCloudOS 9：firewalld优先 + iptables双保险）
#    规则顺序严格：ESTABLISHED → lo → 主力端口
# ============================================================
echo -e "\n${YELLOW}[9/12] 配置防火墙（firewalld + iptables 双保险）...${NC}"

# ---------- firewalld 优先（OpenCloudOS 9默认） ----------
if systemctl is-active firewalld >/dev/null 2>&1; then
    echo -e "  ${CYAN}firewalld运行中，添加规则...${NC}"
    firewall-cmd --permanent --add-port=${VPN_PORT}/${PROTOCOL} 2>/dev/null || true
    firewall-cmd --permanent --add-port=443/udp 2>/dev/null || true
    firewall-cmd --permanent --add-port=443/tcp 2>/dev/null || true
    firewall-cmd --permanent --add-port=22/tcp 2>/dev/null || true
    firewall-cmd --permanent --add-port=80/tcp 2>/dev/null || true
    firewall-cmd --permanent --add-port=3389/tcp 2>/dev/null || true
    firewall-cmd --permanent --add-port=3389/udp 2>/dev/null || true
    firewall-cmd --permanent --add-port=1194/tcp 2>/dev/null || true
    firewall-cmd --permanent --add-port=1195/udp 2>/dev/null || true
    # Pi Node 端口：31400-31409（公网→VPN内网端口转发用）
    firewall-cmd --permanent --add-port=31400-31409/tcp 2>/dev/null || true
    firewall-cmd --permanent --add-port=31400-31409/udp 2>/dev/null || true
    # 地址伪装（VPN客户端上网必须！）
    firewall-cmd --permanent --add-masquerade 2>/dev/null || true
    firewall-cmd --reload 2>/dev/null || true
    echo -e "  ${GREEN}✓ firewalld配置完成${NC}"
else
    echo -e "  ${YELLOW}⚠ firewalld未运行，跳过，使用iptables${NC}"
    # 没开firewalld时，手动确保masquerade和转发内核参数
    echo 1 > /proc/sys/net/ipv4/ip_forward
fi

# ---------- iptables 双保险（幂等添加，绝不-F清空！） ----------
ipt_add() {
    iptables -C INPUT "$@" 2>/dev/null || iptables -A INPUT "$@" 2>/dev/null || true
}
ipt_add_fwd() {
    iptables -C FORWARD "$@" 2>/dev/null || iptables -A FORWARD "$@" 2>/dev/null || true
}
ipt_add_nat() {
    iptables -t nat -C POSTROUTING "$@" 2>/dev/null || iptables -t nat -A POSTROUTING "$@" 2>/dev/null || true
}

# 关键顺序：先放ESTABLISHED → 再lo → 再主力端口（避免已有SSH被阻断）
ipt_add -m state --state ESTABLISHED,RELATED -j ACCEPT
ipt_add -i lo -j ACCEPT

# 主力端口：UDP 1194（必须确保放行！）
ipt_add -p $PROTOCOL --dport $VPN_PORT -j ACCEPT
# 备用穿透端口
ipt_add -p udp --dport 443 -j ACCEPT
ipt_add -p tcp --dport 443 -j ACCEPT
ipt_add -p tcp --dport 1194 -j ACCEPT
ipt_add -p udp --dport 1195 -j ACCEPT
# 基础运维端口
ipt_add -p tcp --dport 22 -j ACCEPT
ipt_add -p tcp --dport 80 -j ACCEPT
ipt_add -p tcp --dport 3389 -j ACCEPT
ipt_add -p udp --dport 3389 -j ACCEPT
# Pi Node 端口段
ipt_add -p tcp --dport 31400:31409 -j ACCEPT
ipt_add -p udp --dport 31400:31409 -j ACCEPT
# Ping
ipt_add -p icmp --icmp-type any -j ACCEPT

# FORWARD链（VPN子网转发）
ipt_add_fwd -m state --state RELATED,ESTABLISHED -j ACCEPT
ipt_add_fwd -i tun0 -j ACCEPT
ipt_add_fwd -s $NETWORK/24 -j ACCEPT
ipt_add_fwd -d $NETWORK/24 -j ACCEPT

# NAT：地址伪装（客户端上网必须！）
ipt_add_nat -s $NETWORK/24 -o $IFACE -j MASQUERADE

# 持久化
iptables-save > /etc/sysconfig/iptables 2>/dev/null || true
systemctl enable iptables 2>/dev/null || true

echo -e "  ${GREEN}✓ 防火墙配置完成${NC}"
echo -e "  ${YELLOW}  已放行:${NC}"
echo -e "    UDP 1194       - OpenVPN主力端口${NC}"
echo -e "    UDP 443        - OpenVPN备用端口${NC}"
echo -e "    TCP 443        - OpenVPN最终SOS端口${NC}"
echo -e "    TCP 22         - SSH${NC}"
echo -e "    TCP 80         - HTTP (密钥下载用)${NC}"
echo -e "    TCP/UDP 3389   - 远程桌面${NC}"
echo -e "    TCP/UDP 31400~31409 - Pi Node端口段${NC}"
echo -e "    ICMP           - Ping${NC}"

# ============================================================
# 10. 启动服务
# ============================================================
echo -e "\n${YELLOW}[10/12] 启动OpenVPN...${NC}"

cat > /etc/systemd/system/openvpn-server@server.service << 'UNITEOF'
[Unit]
Description=OpenVPN Server Service (OC9-MAIN UDP 1194)
After=network.target

[Service]
Type=simple
WorkingDirectory=/etc/openvpn/server
ExecStart=/usr/sbin/openvpn /etc/openvpn/server/server.conf
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
UNITEOF

systemctl daemon-reload
systemctl enable openvpn-server@server 2>/dev/null || true
systemctl start openvpn-server@server

sleep 3

if systemctl is-active openvpn-server@server >/dev/null 2>&1; then
    echo -e "  ${GREEN}✓ OpenVPN启动成功${NC}"
else
    echo -e "${RED}✗ OpenVPN启动失败${NC}"
    journalctl -u openvpn-server@server --no-pager -n 20
    exit 1
fi

# ============================================================
# 11. 部署验证（13项全检，一次确认，避免后续反复出问题）
# ============================================================
echo -e "\n${YELLOW}[11/12] 13项部署验证（必须全通过）...${NC}"

ERRORS=0

check_pass() { echo -e "  ${GREEN}✓ $1${NC}"; }
check_fail() { echo -e "  ${RED}✗ $1${NC}"; ERRORS=$((ERRORS + 1)); }

# 1. 服务状态
systemctl is-active openvpn-server@server >/dev/null 2>&1 && check_pass "1. 服务运行中" || check_fail "1. 服务未运行"

# 2. 端口监听（UDP 1194）
if ss -ulnp 2>/dev/null | grep -q ":$VPN_PORT "; then
    check_pass "2. UDP $VPN_PORT 端口正常监听"
else
    check_fail "2. UDP $VPN_PORT 端口未监听"
fi

# 3. IP转发
[ "$(sysctl net.ipv4.ip_forward 2>/dev/null | awk '{print $3}')" = "1" ] && check_pass "3. IP转发已开启" || check_fail "3. IP转发未开启"

# 4. NAT伪装规则
iptables -t nat -L -n 2>/dev/null | grep -q "MASQUERADE" && check_pass "4. NAT伪装规则正常" || check_fail "4. NAT伪装规则缺失"

# 5. tun0接口
if ip addr show tun0 >/dev/null 2>&1; then
    TUN_IP=$(ip addr show tun0 2>/dev/null | grep -oP 'inet\s+\K[0-9.]+' || echo "")
    check_pass "5. tun0接口正常 (IP: $TUN_IP)"
else
    check_fail "5. tun0接口不存在"
fi

# 6. OVPN文件完整性
if [ -f "/root/$CLIENT_NAME.ovpn" ] && grep -q "BEGIN CERTIFICATE" /root/$CLIENT_NAME.ovpn && grep -q "BEGIN PRIVATE KEY" /root/$CLIENT_NAME.ovpn; then
    check_pass "6. OVPN文件完整 (CA+证书+私钥)"
else
    check_fail "6. OVPN文件不完整"
fi

# 7. 加密配置（对齐3-17-2能连版本：cipher AES-256-CBC，不指定data-ciphers让客户端自动协商）
grep -q "cipher AES-256-CBC" /etc/openvpn/server/server.conf && check_pass "7. AES-256-CBC加密已启用（3-17-2对齐）" || check_fail "7. cipher配置缺失"

# 8. SHA512认证（对齐3-17-2能连版本）
grep -q "auth SHA512" /etc/openvpn/server/server.conf && grep -q "auth SHA512" /root/$CLIENT_NAME.ovpn && check_pass "8. SHA512认证已启用（3-17-2对齐）" || check_fail "8. SHA512认证缺失"

# 9. mssfix 1200（3.x兼容，替代fragment，白屏修复）
grep -q "mssfix 1200" /etc/openvpn/server/server.conf && check_pass "9. 包大小控制已启用 (mssfix1200 · 3.x兼容)" || check_fail "9. mssfix参数缺失"

# 10. 死会话清理 + 断开重连 + 抗抖保活（3.5新增keepalive 180）
if grep -q "inactive 60" /etc/openvpn/server/server.conf && \
   grep -q "duplicate-cn" /etc/openvpn/server/server.conf && \
   grep -q "keepalive 10 180" /etc/openvpn/server/server.conf && \
   grep -q "reneg-sec 0" /etc/openvpn/server/server.conf; then
    check_pass "10. 抗抖保活+断开重连 (keepalive180+inactive60+duplicate-cn+reneg0)"
else
    check_fail "10. 保活/重连参数缺失"
fi

# 11. tls-crypt加密防火墙（防DoS，3.7新增，替代tls-auth，OpenVPN 3.x完全兼容）
if [ -f /etc/openvpn/server/ta.key ] && \
   grep -q "tls-crypt" /etc/openvpn/server/server.conf && \
   grep -q "BEGIN OpenVPN Static key" /root/$CLIENT_NAME.ovpn; then
    check_pass "11. tls-crypt加密防火墙已启用（防DoS/端口扫描，3.x兼容）"
else
    check_fail "11. tls-crypt防火墙配置缺失"
fi

# 12. 服务端mssfix+replay-window（3.8版：仅服务端保留，客户端不指定，对齐3-17-2能连版本）
if grep -q "mssfix 1200" /etc/openvpn/server/server.conf && \
   grep -q "replay-window" /etc/openvpn/server/server.conf; then
    check_pass "12. 服务端mssfix+replay-window已启用（客户端不指定，3-17-2对齐）"
else
    check_fail "12. 服务端mssfix/replay-window配置缺失"
fi

# 13. BBR拥塞控制
[ "$(sysctl net.ipv4.tcp_congestion_control 2>/dev/null | awk '{print $3}')" = "bbr" ] && check_pass "13. BBR拥塞控制已启用" || check_pass "13. BBR: $(sysctl net.ipv4.tcp_congestion_control 2>/dev/null | awk '{print $3}')（内核不支持则跳过）"

if [ "$ERRORS" -gt 0 ]; then
    echo -e "\n${RED}✗ 验证发现 $ERRORS 个问题，请检查上面的 ✗ 项${NC}"
else
    echo -e "\n${GREEN}✓ 13项全部验证通过！部署质量确认${NC}"
fi

# ============================================================
# 12. 部署完成信息
# ============================================================
echo -e "\n${YELLOW}[12/12] 生成密钥下载链接...${NC}"

mkdir -p /var/www/html 2>/dev/null || true
cp -f /root/$CLIENT_NAME.ovpn /var/www/html/$CLIENT_NAME.ovpn 2>/dev/null || true
cp -f /root/$CLIENT_NAME.ovpn /usr/share/nginx/html/$CLIENT_NAME.ovpn 2>/dev/null || true

# 若80端口未占用，用python起临时HTTP服务下载密钥
if ! ss -tlnp 2>/dev/null | grep -q ":80 "; then
    cd /root && nohup python3 -m http.server 80 >/tmp/http.log 2>&1 &
    cd /root && nohup python -m SimpleHTTPServer 80 >/tmp/http.log 2>&1 &
fi
sleep 1

echo -e "\n${GREEN}==============================================${NC}"
echo -e "${GREEN}  OpenCloudOS 9 主力版部署完成！${NC}"
echo -e "${GREEN}==============================================${NC}"
echo -e ""
echo -e "${YELLOW}【服务器信息】${NC}"
echo -e "  公网IP:    $PUBLIC_IP"
echo -e "  系统:      $(cat /etc/opencloudos-release 2>/dev/null || cat /etc/os-release | grep PRETTY_NAME | head -1)"
echo -e "  OpenVPN:   v${OVPN_VERSION}"
echo -e "  包管理:    $PKG_MGR"
echo -e ""
echo -e "${YELLOW}【VPN配置 - 主力版 UDP 1194】${NC}"
echo -e "  客户端名:  $CLIENT_NAME（一机一证，8台运行pc0~pc7）"
echo -e "  协议端口:  UDP 1194（延迟低，Pi Node不白屏首选）"
echo -e "  VPN子网:   $NETWORK/24"
echo -e "  最大连接:  $MAX_CLIENTS（8台留双倍余量防占坑）"
echo -e ""
echo -e "${YELLOW}【已启用的稳定优化】${NC}"
echo -e "  ✓ mssfix 1200 → 3.x兼容，控制包≤1200字节，防大UDP包被丢${NC}"
echo -e "  ✓ replay-window 1024 30 → 扩大重放窗口，防Packet ID replay${NC}"
echo -e "  ✓ fast-io → UDP高并发减少syscall${NC}"
echo -e "  ✓ explicit-exit-notify 1 → 减少UDP会话假死${NC}"
echo -e "  ✓ keepalive 10 180 + reneg-sec 0 → 抗抖保活，解决频繁掉线${NC}"
echo -e "  ✓ duplicate-cn + inactive 60 → 断开后立即重连，1分钟回收IP${NC}"
echo -e "  ✓ max-clients $MAX_CLIENTS → 不占坑${NC}"
echo -e "  ✓ BBR + 64MB UDP缓冲区 → 并发不丢包${NC}"
echo -e "  ✓ 防火墙顺序正确 → 不会意外阻断SSH${NC}"
echo -e "  ✓ tls-crypt加密防火墙 → 防DoS和端口扫描（3.x完全兼容）${NC}"
echo -e "  ✓ 权限降级 nobody/nobody → 安全加固${NC}"
echo -e "  ✓ tls-version-min 1.2 → 禁用弱TLS${NC}"
echo -e "  ✓ ifconfig-pool-persist → 重连IP稳定${NC}"
echo -e ""
echo -e "${YELLOW}【下载OVPN密钥】${NC}"
echo -e "  浏览器直接下载: http://$PUBLIC_IP/$CLIENT_NAME.ovpn"
echo -e "  或scp命令:      scp root@$PUBLIC_IP:/root/$CLIENT_NAME.ovpn ./"
echo -e "  文件路径:       /root/$CLIENT_NAME.ovpn"
echo -e ""
echo -e "${RED}【重要 - 腾讯云安全组必须放行】${NC}"
echo -e "  类型: 自定义 | 协议: UDP | 端口: 1194 | 来源: 0.0.0.0/0${NC}"
echo -e "  类型: 自定义 | 协议: TCP | 端口: 22   | 来源: 0.0.0.0/0${NC}"
echo -e "  类型: 自定义 | 协议: TCP | 端口: 80   | 来源: 0.0.0.0/0${NC}"
echo -e "  类型: 自定义 | 协议: UDP | 端口: 443  | 来源: 0.0.0.0/0 【备用SOS用】${NC}"
echo -e "  类型: 自定义 | 协议: TCP | 端口: 443  | 来源: 0.0.0.0/0 【最终SOS用】${NC}"
echo -e "  类型: 自定义 | 协议: TCP+UDP | 端口: 31400-31409 【Pi Node端口映射用】${NC}"
echo -e ""
echo -e "${YELLOW}【生成第2~8台虚拟机密钥（如使用一对一云端则忽略此段）】${NC}"
echo -e "  第2台(pc1): bash /root/openvpn-oc9-main.sh pc1${NC}"
echo -e "  第3台(pc2): bash /root/openvpn-oc9-main.sh pc2${NC}"
echo -e "  ... 一对一云端场景每台服务器只跑一次即可，duplicate-cn允许重连${NC}"
echo -e ""
echo -e "${YELLOW}【诊断命令】${NC}"
echo -e "  服务状态: systemctl status openvpn-server@server --no-pager"
echo -e "  连接状态: cat /etc/openvpn/server/status.log"
echo -e "  实时日志: tail -f /etc/openvpn/server/openvpn.log"
echo -e "  抓包测试: tcpdump -i $IFACE udp port 1194 -nn"
echo -e "  NAT检查:  iptables -t nat -L -n"
echo -e "  UDP连不上时用SOS版: bash openvpn-oc9-sos.sh"
echo -e "${GREEN}==============================================${NC}"
