#!/bin/bash
clear
sleep 1
# 设置文字颜色为亮绿色，显示标题和说明
echo -e "\e[1;32m"
echo -e "一键全自动安装 OpenVPN (默认TCP协议) + 端口映射"
echo -e "修改请保留原作者信息 | 适配 Pi Node 节点隧道"
echo "========================================================="
echo -e "                    重 要 说 明                  "
echo ""
echo -e "1. 仅限 Pi Node 节点建立隧道使用，禁止其他用途"
echo ""
echo -e "2. 必须遵守当地法律法规，非法使用后果自负"
echo ""
echo -e "3. 脚本功能：全自动安装OpenVPN + 端口映射（10个连续端口）"
echo ""
echo -e "4. 适用系统：Linux Ubuntu v20.04.1 x64（推荐）及兼容系统"
echo ""
echo -e "5. 运行要求：必须拥有root管理员权限（sudo）"
echo ""
echo -e "6. 常见问题：若出现「Peer certificate verification failure」错误，脚本将自动检测修复"  # 【新增】证书错误提示
echo "========================================================="
echo -ne "\e[0m"  # 恢复默认文字颜色

# 【新增】证书验证失败预处理函数（提前检查依赖与环境）
pre_check_cert_env() {
    echo -e "\n\e[1;33m=== 预处理：检查证书生成依赖环境（预防Peer certificate verification failure） ===\e[0m"
    # 检查openssl是否安装（证书生成必需）
    if ! hash openssl 2>/dev/null; then
        echo -e "\e[1;31m检测到openssl未安装，证书生成将失败，正在自动安装...\e[0m"
        if ! sudo apt-get install -y openssl; then
            echo -e "\e[1;31mopenssl安装失败，可能导致后续证书验证错误，请手动执行 sudo apt-get install -y openssl 后重试\e[0m"
            exit 1
        fi
    fi
    # 检查系统时间同步（证书有效期依赖正确时间）
    current_time=$(date +%s)
    ntp_time=$(curl -sI http://www.baidu.com | grep -i 'date:' | awk '{print $3,$4,$5,$6,$7}' | xargs -I {} date -d "{}" +%s 2>/dev/null)
    if [ -n "$ntp_time" ] && [ $((current_time - ntp_time)) -gt 300 ] || [ $((ntp_time - current_time)) -gt 300 ]; then
        echo -e "\e[1;31m系统时间与网络时间偏差超过5分钟，可能导致证书验证失败，正在同步时间...\e[0m"
        # 安装时间同步工具并同步
        if ! sudo apt-get install -y ntpdate; then
            echo -e "\e[1;33mntpdate安装失败，尝试手动同步时间...\e[0m"
            sudo date -s "$(curl -sI http://www.baidu.com | grep -i 'date:' | awk '{print $3,$4,$5,$6,$7}')" 2>/dev/null || echo -e "\e[1;31m手动时间同步失败，请检查网络后手动调整系统时间\e[0m"
        else
            sudo ntpdate pool.ntp.org >/dev/null 2>&1
            echo -e "\e[1;32m系统时间同步完成！\e[0m"
        fi
    else
        echo -e "\e[1;32mopenssl已安装，系统时间正常，跳过预处理修复\e[0m"
    fi
}

# 【新增】端口选择函数（支持默认/自定义/随机4位数）
select_custom_port() {
    echo -e "\n\e[1;33m请选择端口配置方式：\e[0m"
    echo "   1) 使用默认端口（OpenVPN: TCP/2868，映射端口: 31400-31409）"
    echo "   2) 自定义端口配置"
    echo "   3) 随机4位数端口配置"
    read -rp "请选择 [1]: " port_choice
    [[ -z "$port_choice" ]] && port_choice=1
    if [[ "$port_choice" -eq 3 ]]; then
        # 随机4位数端口配置
        echo -e "\n\e[1;33m正在生成随机4位数端口...\e[0m"
        ovpn_port=$((RANDOM % 9000 + 1000))  # 生成1000-9999的随机端口
        map_start=$((RANDOM % 9000 + 1000))  # 生成1000-9999的随机映射起始端口
        # 确保结束端口不超过65535
        map_end=$((map_start + 9))
        if [[ "$map_end" -gt 65535 ]]; then
            map_end=65535
            echo -e "\e[1;33m警告：端口范围超出上限，自动调整为 $map_start-$map_end\e[0m"
        fi
    elif [[ "$port_choice" -eq 2 ]]; then
        # 自定义OpenVPN端口
        echo -e "\n\e[1;33m请输入OpenVPN端口（1-65535）：\e[0m"
        read -rp "OpenVPN端口 [2868]: " ovpn_port
        until [[ -z "$ovpn_port" || "$ovpn_port" =~ ^[0-9]+$ && "$ovpn_port" -le 65535 && "$ovpn_port" -ge 1 ]]; do
            echo -e "\e[1;31m无效端口！请输入1-65535之间的数字\e[0m"
            read -rp "OpenVPN端口 [2868]: " ovpn_port
        done
        [[ -z "$ovpn_port" ]] && ovpn_port=2868
        # 自定义映射端口范围（起始端口）
        echo -e "\n\e[1;33m请输入端口映射起始端口（1-65534，将自动生成10个连续端口）：\e[0m"
        read -rp "起始端口 [31400]: " map_start
        until [[ -z "$map_start" || "$map_start" =~ ^[0-9]+$ && "$map_start" -le 65534 && "$map_start" -ge 1 ]]; do
            echo -e "\e[1;31m无效端口！请输入1-65534之间的数字\e[0m"
            read -rp "起始端口 [31400]: " map_start
        done
        [[ -z "$map_start" ]] && map_start=31400
        # 计算结束端口（起始端口+9），避免超出上限
        map_end=$((map_start + 9))
        if [[ "$map_end" -gt 65535 ]]; then
            map_end=65535
            echo -e "\e[1;33m警告：端口范围超出上限，自动调整为 $map_start-$map_end\e[0m"
        fi
    else
        # 默认端口配置
        ovpn_port=2868
        map_start=31400
        map_end=31409
    fi
    # 显示最终端口配置并确认
    echo -e "\n\e[1;32m端口配置确认：\e[0m"
    echo "OpenVPN端口：TCP/$ovpn_port"
    echo "映射端口范围：$map_start-$map_end"
    read -n 1 -s -r -p "按任意键继续安装..."
}

# 【新增】客户端证书配置检测函数（处理Peer certificate verification failure）
check_client_cert() {
    local client_name="pinode"
    local export_dir=~/
    # 若使用sudo，获取原用户目录
    if [ -n "$SUDO_USER" ] && getent group "$SUDO_USER" >/dev/null 2>&1; then
        local user_home_dir=$(getent passwd "$SUDO_USER" 2>/dev/null | cut -d: -f6)
        if [ -d "$user_home_dir" ] && [ "$user_home_dir" != "/" ]; then
            export_dir="$user_home_dir/"
        fi
    fi
    local ovpn_file="$export_dir$client_name.ovpn"

    echo -e "\n\e[1;33m=== 检测客户端证书配置（预防Peer certificate verification failure） ===\e[0m"
    # 检查客户端配置文件是否存在
    if [ ! -f "$ovpn_file" ]; then
        echo -e "\e[1;31m客户端配置文件 $ovpn_file 不存在，可能导致连接失败\e[0m"
        return 1
    fi
    # 检查配置文件中关键证书块是否完整
    local cert_blocks=("</ca>" "</cert>" "</key>" "</tls-crypt>")
    local block_missing=0
    for block in "${cert_blocks[@]}"; do
        if ! grep -qs "$block" "$ovpn_file"; then
            echo -e "\e[1;31m客户端配置文件缺失 $block 块，将导致证书验证失败\e[0m"
            block_missing=1
        fi
    done
    # 若缺失证书块，重新调用openvpn.sh生成配置
    if [ "$block_missing" -eq 1 ]; then
        echo -e "\e[1;33m正在重新生成客户端配置文件以修复证书块...\e[0m"
        if ! sudo bash openvpn.sh --auto --port "$ovpn_port"; then
            echo -e "\e[1;31m重新生成客户端配置失败，请手动执行 sudo bash openvpn.sh 选择「导出已有客户端配置」\e[0m"
            return 1
        else
            echo -e "\e[1;32m客户端配置文件重新生成完成，证书块已补全\e[0m"
        fi
    else
        echo -e "\e[1;32m客户端配置文件证书块完整，跳过修复\e[0m"
    fi

    # 验证证书文件有效性（通过openssl命令）
    echo -e "\n\e[1;33m验证服务器端证书有效性...\e[0m"
    local server_cert="/etc/openvpn/server/server.crt"
    local ca_cert="/etc/openvpn/server/ca.crt"
    if [ -f "$server_cert" ] && [ -f "$ca_cert" ]; then
        # 检查证书是否过期或损坏
        if ! openssl x509 -in "$server_cert" -noout -text >/dev/null 2>&1; then
            echo -e "\e[1;31m服务器证书 $server_cert 损坏，将导致证书验证失败\e[0m"
            echo -e "\e[1;33m尝试修复服务器证书...\e[0m"
            sudo bash openvpn.sh <<EOF
6
EOF
        elif ! openssl verify -CAfile "$ca_cert" "$server_cert" >/dev/null 2>&1; then
            echo -e "\e[1;31m服务器证书 $server_cert 验证不通过，可能是CA证书不匹配\e[0m"
            echo -e "\e[1;33m尝试重新生成证书链...\e[0m"
            sudo bash openvpn.sh <<EOF
6
EOF
        else
            echo -e "\e[1;32m服务器证书验证通过，有效期正常\e[0m"
        fi
    else
        echo -e "\e[1;31m服务器证书 $server_cert 或 CA证书 $ca_cert 缺失\e[0m"
        return 1
    fi
    return 0
}

# 【新增】证书验证失败手动修复指南显示函数
show_cert_fix_guide() {
    echo -e "\n\e[1;32m=== Peer certificate verification failure 手动修复指南 ===\e[0m"
    echo -e "若客户端连接时出现「证书验证失败」错误，请按以下步骤排查："
    echo -e "1. 检查客户端配置文件完整性："
    echo -e "   - 确认 $export_dir$client_name.ovpn 文件存在，且大小大于10KB（过小则证书缺失）"
    echo -e "   - 用文本编辑器打开文件，确认包含 <ca>、<cert>、<key>、<tls-crypt> 完整内容（无截断）"
    echo -e "2. 重新生成客户端配置："
    echo -e "   - 执行命令：sudo bash openvpn.sh"
    echo -e "   - 选择选项 2「导出已有客户端配置」，重新下载配置文件"
    echo -e "3. 修复服务器证书链："
    echo -e "   - 执行命令：sudo bash openvpn.sh"
    echo -e "   - 选择选项 6「Fix Peer certificate verification failure」自动修复"
    echo -e "4. 同步系统时间（证书有效期依赖正确时间）："
    echo -e "   - 执行命令：sudo apt-get install -y ntpdate && sudo ntpdate pool.ntp.org"
    echo -e "5. 验证端口映射与防火墙："
    echo -e "   - 确认OpenVPN端口已开放：sudo ufw allow $ovpn_port/tcp（仅Ubuntu）"
    echo -e "   - 确认端口映射正常：sudo systemctl status port-mapping"
    echo -e "======================================================\e[0m"
}

# 调用端口选择函数
select_custom_port
# 【新增】执行证书环境预处理
pre_check_cert_env
# 等待用户确认开始安装
echo -e "\n\n按任意键开始全自动安装（端口映射重启后不失效）:"
read -n 1 -s -r -p ""
# 检查是否为root用户（无root权限则退出）
if [ "$(id -u)" -ne 0 ]; then
    echo -e "\n\e[1;31m错误：此脚本需要root权限运行，请使用 sudo bash 脚本名.sh 执行\e[0m"
    exit 1
fi
# 检查openvpn.sh是否存在（不存在则提示并退出）
if [ ! -f "openvpn.sh" ]; then
    echo -e "\n\e[1;31m错误：未找到 openvpn.sh 文件，请将其与本脚本放在同一目录\e[0m"
    exit 1
fi
# 【修改】执行OpenVPN自动安装（传入自定义端口）
echo -e "\n\e[1;33m正在全自动安装OpenVPN（TCP/$ovpn_port）...\e[0m"
if ! sudo bash openvpn.sh --auto --port "$ovpn_port"; then
    echo -e "\e[1;31mOpenVPN安装失败，请检查系统环境或网络连接\e[0m"
    exit 1
fi
# 【新增】安装完成后检测客户端证书配置
check_client_cert
# 安装redir（端口映射工具）
echo -e "\n\e[1;33m正在安装端口映射工具（redir）...\e[0m"
if ! sudo apt-get install -y redir; then
    echo -e "\e[1;31mredir安装失败，请手动执行 sudo apt-get install -y redir 后重试\e[0m"
    exit 1
fi
# 安装net-tools（网络状态查看工具，如netstat）
echo -e "\n\e[1;33m正在安装网络工具（net-tools）...\e[0m"
if ! sudo apt-get install -y net-tools; then
    echo -e "\e[1;31mnet-tools安装失败，请手动执行 sudo apt-get install -y net-tools 后重试\e[0m"
    exit 1
fi
# 【修改】创建Systemd服务文件（使用自定义映射端口）
echo -e "\n\e[1;33m正在配置端口映射服务（$map_start-$map_end -> 10.8.0.2）...\e[0m"
cat <<EOF > /etc/systemd/system/port-mapping.service
[Unit]
Description=TCP Port Mapping Service for Pi Node ($map_start-$map_end -> 10.8.0.2)
After=network.target openvpn-server@server.service
# 依赖OpenVPN服务，确保OpenVPN启动后再启动映射
[Service]
Type=simple
# 显式使用TCP协议，将自定义端口范围映射到10.8.0.2（VPN客户端默认IP）
ExecStart=/bin/bash -c 'for ((port=$map_start; port<=$map_end; port++)); do redir -t ":$port" "10.8.0.2:$port"; done'
Restart=on-failure  # 服务异常时自动重启
RestartSec=5        # 重启间隔5秒
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
# 检查服务文件是否创建成功
if [ ! -f /etc/systemd/system/port-mapping.service ]; then
    echo -e "\e[1;31m端口映射服务文件创建失败，请检查目录权限\e[0m"
    exit 1
fi
# 重新加载Systemd配置（使新服务生效）
echo -e "\n\e[1;33m正在加载系统服务配置...\e[0m"
if ! systemctl daemon-reload; then
    echo -e "\e[1;31mSystemd配置重载失败，请手动执行 sudo systemctl daemon-reload 后重试\e[0m"
    exit 1
fi
# 启用端口映射服务（开机自启）
echo -e "\n\e[1;33m正在设置端口映射服务开机自启...\e[0m"
if ! systemctl enable port-mapping.service; then
    echo -e "\e[1;31m端口映射服务启用失败，请手动执行 sudo systemctl enable port-mapping.service 后重试\e[0m"
    exit 1
fi
# 启动端口映射服务
echo -e "\n\e[1;33m正在启动端口映射服务...\e[0m"
if ! systemctl start port-mapping.service; then
    echo -e "\e[1;31m端口映射服务启动失败，请手动执行 sudo systemctl start port-mapping.service 后重试\e[0m"
    exit 1
fi
# 【新增】手动执行端口映射命令，确保即时生效（解决服务启动延迟问题）
echo -e "\n\e[1;33m正在手动执行端口映射，确保端口即时可用...\e[0m"
sudo redir :31400 10.8.0.2:31400
sudo redir :31401 10.8.0.2:31401
sudo redir :31402 10.8.0.2:31402
sudo redir :31403 10.8.0.2:31403
sudo redir :31404 10.8.0.2:31404
sudo redir :31405 10.8.0.2:31405
sudo redir :31406 10.8.0.2:31406
sudo redir :31407 10.8.0.2:31407
sudo redir :31408 10.8.0.2:31408
sudo redir :31409 10.8.0.2:31409
# 等待10秒，确保服务完全启动
echo -e "\n\e[1;33m等待服务启动，10秒后查看映射状态...\e[0m"
sleep 10
# 显示当前TCP端口映射状态（仅显示redir相关进程）
echo -e "\n\e[1;32m==================== 安装完成 ====================\e[0m"
echo -e "\e[1;32m当前TCP端口映射状态（仅显示redir进程）：\e[0m"
netstat -tulnp | grep redir || echo -e "\e[1;33m提示：未找到redir进程，可稍后执行 netstat -tulnp | grep redir 查看\e[0m"

# 【新增】显示证书验证失败修复指南
show_cert_fix_guide

# 显示安装结果总结
echo -e "\n\e[1;32m==================== 配置总结 ====================\e[0m"
echo -e "1. OpenVPN服务：已安装（TCP/$ovpn_port），开机自启"
echo -e "2. 客户端配置：默认路径 ~/pinode.ovpn（或原用户目录）"
echo -e "3. 端口映射：远程TCP($map_start-$map_end) -> 本地10.8.0.2，已手动执行确保连通"
echo -e "4. 查看OpenVPN状态：sudo systemctl status openvpn-server@server"
echo -e "5. 查看端口映射状态：sudo systemctl status port-mapping"
echo -e "6. 证书修复命令：sudo bash openvpn.sh（选择选项6「Fix Peer certificate verification failure」）"  # 【新增】证书修复命令提示
echo -e "\n\e[1;32m安装完成！可使用客户端配置文件连接OpenVPN\e[0m"
exit 0