#!/bin/bash # Shadowsocks 管理脚本 - 集成安装、卸载和管理功能 # 专门支持 shadowsocks-libev 协议 # 使用方法: chmod +x shadowsocks-manager.sh && ./shadowsocks-manager.sh # 使用方法: chmod +x ss2022-manager.sh && ./ss2022-manager.sh # 全局变量 SS_PATH="/usr/local/bin" CONFIG_PATH="/etc/shadowsocks-libev" SS_PORT="" # Shadowsocks 端口 LOG_PATH="/var/log/shadowsocks" LOG_FILE="/var/log/shadowsocks-manager.log" SCRIPT_VERSION="1.0.0" SS_PASSWORD="" SS_METHOD="aes-128-gcm" # 默认使用 AEAD 加密方法 CONFIG_BACKUP="" SERVER_IP="" # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' # No Color # 进度条函数 show_progress() { local pid=$1 local delay=0.1 local spinstr='|/-\' local temp local count=0 local start_time=$(date +%s) echo -n " " while ps -p $pid > /dev/null; do temp=${spinstr#?} printf "\r[%c] %s 已进行 %ds" "$spinstr" "$2" "$(($(date +%s) - start_time))" spinstr=$temp${spinstr%"$temp"} sleep $delay count=$((count + 1)) done printf "\r\033[K" } # 进度条显示函数 - 适用于apt操作 apt_progress() { local cmd="$1" local msg="$2" local logfile="$LOG_FILE.tmp" echo -e "${CYAN}开始 $msg...${NC}" touch "$logfile" ($cmd 2>&1 | tee -a "$LOG_FILE" > "$logfile") & local pid=$! # 显示进度条 local start_time=$(date +%s) local dots="" local status="" local progress=0 local last_line="" local delay=0.2 while ps -p $pid > /dev/null; do # 读取最后一行日志 if [[ -f "$logfile" ]]; then last_line=$(tail -n 1 "$logfile") # 尝试从输出中提取进度信息 if [[ $last_line == *%* ]]; then status="${last_line%%(*}" progress="${last_line#*(}" progress="${progress%%)*}" printf "\r\033[K${CYAN}[$msg]${NC} %s %s " "$status" "$progress" else dots="${dots}." if [[ ${#dots} -gt 5 ]]; then dots="."; fi elapsed=$(($(date +%s) - start_time)) printf "\r\033[K${CYAN}[$msg]${NC} 进行中%s (%ds)" "$dots" "$elapsed" fi fi sleep $delay done if wait $pid; then printf "\r\033[K${GREEN}[$msg]${NC} 完成! 用时: %ds\n" "$(($(date +%s) - start_time))" rm -f "$logfile" return 0 else printf "\r\033[K${RED}[$msg]${NC} 失败! 查看日志: $LOG_FILE\n" rm -f "$logfile" return 1 fi } # 日志函数 log_info() { echo -e "${GREEN}[INFO]${NC} $1" | tee -a "$LOG_FILE" } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" | tee -a "$LOG_FILE" } log_error() { echo -e "${RED}[ERROR]${NC} $1" >&2 | tee -a "$LOG_FILE" } log_debug() { echo -e "${BLUE}[DEBUG]${NC} $1" | tee -a "$LOG_FILE" } # 检查是否有 root 权限 check_root() { if [[ $EUID -ne 0 ]]; then log_error "此脚本需要 root 权限运行" exit 1 fi } # 检查系统环境 check_system() { # 显示系统信息 echo "系统信息:" echo "------------------------" if [ -f /etc/os-release ]; then cat /etc/os-release | grep "PRETTY_NAME" | cut -d= -f2- | tr -d '"' fi echo "内核版本: $(uname -r)" echo "架构: $(uname -m)" echo "------------------------" # 检查是否为 Debian/Ubuntu 系统 if [[ ! -f /etc/debian_version && ! -f /etc/lsb-release ]]; then log_warn "未检测到 Debian/Ubuntu 系统,脚本可能无法正常工作" read -rp "是否继续? [y/N] " response if [[ ! "$response" =~ ^[yY]$ ]]; then exit 1 fi fi # 检查网络连接 echo -n "检查网络连接... " if ping -c 1 -W 2 github.com &>/dev/null; then echo -e "${GREEN}连接正常${NC}" else echo -e "${YELLOW}无法连接到 GitHub${NC}" log_warn "无法连接到 GitHub,请检查网络连接" read -rp "是否继续? [y/N] " response if [[ ! "$response" =~ ^[yY]$ ]]; then exit 1 fi fi } # 备份函数 backup_config() { if [[ -d "$CONFIG_PATH" ]]; then CONFIG_BACKUP="${CONFIG_PATH}_backup_$(date +%Y%m%d%H%M%S)" log_info "备份现有配置到 $CONFIG_BACKUP" cp -r "$CONFIG_PATH" "$CONFIG_BACKUP" || log_warn "配置备份失败" # 备份 Shadowsocks 信息文件 if [[ -f "/root/shadowsocks_info.txt" ]]; then cp "/root/shadowsocks_info.txt" "${CONFIG_BACKUP}/shadowsocks_info.txt.bak" || log_warn "Shadowsocks 信息文件备份失败" fi else log_warn "找不到配置目录,跳过备份" fi } # 显示帮助信息 show_help() { echo "Shadowsocks 管理脚本 v${SCRIPT_VERSION}" echo "用法: $0 [选项]" echo "" echo "选项:" echo " -h, --help 显示此帮助信息" echo " -i, --install 直接运行安装" echo " -u, --uninstall 直接运行卸载" echo " -s, --status 查看 Shadowsocks 状态" echo " -up, --update 更新 Shadowsocks" echo "" echo "无参数运行脚本将显示交互式菜单" } # 菜单函数 show_menu() { clear echo "==================================================" echo -e "${CYAN}Shadowsocks 管理脚本 v${SCRIPT_VERSION}${NC}" echo -e "${CYAN}(shadowsocks-libev)${NC}" echo "==================================================" echo -e "1) ${GREEN}安装 Shadowsocks${NC}" echo -e "2) ${RED}卸载 Shadowsocks${NC}" echo -e "3) ${YELLOW}更新 Shadowsocks${NC}" echo -e "4) ${BLUE}查看 Shadowsocks 状态${NC}" echo -e "5) ${CYAN}查看 Shadowsocks 配置信息${NC}" echo -e "6) ${GREEN}重启 Shadowsocks 服务${NC}" echo -e "7) ${YELLOW}修改服务器配置${NC}" echo -e "0) ${RED}退出${NC}" echo "==================================================" echo "" read -rp "请输入选项 [0-7]: " choice case $choice in 1) install_shadowsocks ;; 2) uninstall_shadowsocks ;; 3) update_shadowsocks ;; 4) check_status ;; 5) show_config ;; 6) restart_service ;; 7) modify_config ;; 0) exit 0 ;; *) log_error "无效选项" && sleep 2 && show_menu ;; esac } # 安装依赖 install_dependencies() { log_info "安装必要依赖" # 更新软件包列表 apt_progress "apt-get update" "更新软件包列表" || { log_error "更新软件包列表失败" return 1 } # 安装必要工具 local deps=(curl wget jq) for dep in "${deps[@]}"; do if ! command -v "$dep" &>/dev/null; then apt_progress "apt-get install -y $dep" "安装 $dep" || { log_error "安装 $dep 失败" return 1 } else log_info "$dep 已安装,跳过" fi done # 检查安装结果 local all_installed=true for dep in "${deps[@]}"; do if ! command -v "$dep" &>/dev/null; then log_error "$dep 安装失败" all_installed=false fi done if [ "$all_installed" = true ]; then log_info "所有依赖安装完成" return 0 else log_error "部分依赖安装失败" return 1 fi } # 安装 shadowsocks-libev install_shadowsocks_libev() { log_info "开始安装 shadowsocks-libev" # 检查是否已安装 if command -v ss-server &>/dev/null; then log_info "检测到已安装的 shadowsocks-libev,将进行更新" # 停止服务 if systemctl is-active shadowsocks-libev &>/dev/null; then echo -n "停止 Shadowsocks 服务... " if systemctl stop shadowsocks-libev &>/dev/null; then echo -e "${GREEN}成功${NC}" else echo -e "${RED}失败${NC}" log_warn "无法停止 Shadowsocks 服务" fi fi fi # 添加 shadowsocks-libev 官方仓库(如果是 Ubuntu) if command -v lsb_release &>/dev/null && [[ $(lsb_release -si) == "Ubuntu" ]]; then local ubuntu_version=$(lsb_release -sr) if [[ $(echo "$ubuntu_version >= 16.04" | bc) -eq 1 ]]; then log_info "添加 shadowsocks-libev 官方 PPA" apt_progress "add-apt-repository -y ppa:max-c-lv/shadowsocks-libev" "添加 PPA 仓库" apt_progress "apt-get update" "更新软件包列表" fi fi # 安装 shadowsocks-libev apt_progress "apt-get install -y shadowsocks-libev" "安装 shadowsocks-libev" || { log_error "安装 shadowsocks-libev 失败" return 1 } # 验证安装 if command -v ss-server &>/dev/null; then log_info "shadowsocks-libev 安装成功" return 0 else log_error "shadowsocks-libev 安装失败" return 1 fi } # 生成随机配置值 generate_random_values() { log_info "生成随机配置值" # 询问用户是否指定端口 if [[ -z "$SS_PORT" ]]; then read -rp "是否指定端口? [y/N] " specify_port if [[ "$specify_port" =~ ^[yY]$ ]]; then # 用户选择指定端口 while true; do read -rp "请输入端口号 (1-65535): " SS_PORT # 验证端口是否为有效数字 if ! [[ "$SS_PORT" =~ ^[0-9]+$ ]] || [ "$SS_PORT" -lt 1 ] || [ "$SS_PORT" -gt 65535 ]; then log_error "无效的端口号,请输入1-65535之间的数字" continue fi # 检查端口是否被占用 if ss -tuln | grep -q ":$SS_PORT "; then log_warn "端口 $SS_PORT 已被占用,请选择其他端口" continue fi log_info "将使用指定端口: $SS_PORT" break done else # 用户选择随机端口 local attempts=0 while [[ "$attempts" -lt 10 ]]; do SS_PORT=$(shuf -i 10000-60000 -n 1) # 检查端口是否被占用 if ! ss -tuln | grep -q ":$SS_PORT "; then log_info "生成随机端口: $SS_PORT" break fi attempts=$((attempts + 1)) done if [[ "$attempts" -eq 10 ]]; then log_warn "无法找到未占用的端口,使用随机端口: $SS_PORT" fi fi fi # 生成密码 if [[ -z "$SS_PASSWORD" ]]; then read -rp "是否指定密码? [y/N] " specify_password if [[ "$specify_password" =~ ^[yY]$ ]]; then while true; do read -rp "请输入密码 (至少8位): " SS_PASSWORD if [[ ${#SS_PASSWORD} -lt 8 ]]; then log_error "密码至少需要8位" continue fi log_info "将使用指定密码" break done else # 生成随机密码 SS_PASSWORD=$(openssl rand -base64 16) log_info "生成随机密码: $SS_PASSWORD" fi fi # 选择加密方法 echo "选择加密方法:" echo "1) chacha20-ietf-poly1305" echo "2) aes-256-gcm" echo "3) aes-192-gcm" echo "4) aes-128-gcm (默认)" read -rp "请选择加密方法 [1-4, 默认4]: " method_choice case $method_choice in 1) SS_METHOD="chacha20-ietf-poly1305" ;; 2) SS_METHOD="aes-256-gcm" ;; 3) SS_METHOD="aes-192-gcm" ;; *) SS_METHOD="aes-128-gcm" ;; esac log_info "选择的加密方法: $SS_METHOD" # 获取服务器IP get_server_ip } # 获取服务器IP get_server_ip() { log_info "获取服务器IP地址" if [[ -n "$SERVER_IP" ]]; then log_info "使用已设置的IP: $SERVER_IP" return 0 fi # 尝试首选方法获取公网IP SERVER_IP=$(curl -s -m 5 https://api.ipify.org 2>/dev/null) # 验证获取到的IP是否为有效IPv4地址 if [[ -n "$SERVER_IP" && "$SERVER_IP" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then log_info "成功获取公网IP: $SERVER_IP" return 0 fi # 如果第一个方法失败,尝试备用方法 local backup_services=("https://ifconfig.me" "https://ip.sb" "https://ipinfo.io/ip") for service in "${backup_services[@]}"; do SERVER_IP=$(curl -s -m 3 "$service" 2>/dev/null) if [[ -n "$SERVER_IP" && "$SERVER_IP" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then log_info "成功从 $service 获取公网IP: $SERVER_IP" return 0 fi done # 如果所有公网IP获取方式都失败,则使用本地IP if command -v hostname &>/dev/null; then SERVER_IP=$(hostname -I 2>/dev/null | awk '{print $1}') fi # 如果hostname命令失败,尝试使用ip命令 if [[ -z "$SERVER_IP" && -x "$(command -v ip)" ]]; then SERVER_IP=$(ip -4 addr show scope global | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -n 1) fi if [[ -n "$SERVER_IP" ]]; then log_warn "无法获取公网IP,使用本地IP: $SERVER_IP" return 0 else log_error "无法获取任何有效IP地址,将使用127.0.0.1作为占位符" SERVER_IP="127.0.0.1" return 1 fi } # 配置 Shadowsocks configure_shadowsocks() { log_info "配置 Shadowsocks" # 生成随机值 generate_random_values # 创建配置目录 mkdir -p "$CONFIG_PATH" mkdir -p "$LOG_PATH" log_info "创建 Shadowsocks 配置文件" # 创建主配置文件 cat > "$CONFIG_PATH/config.json" << EOF { "server": "0.0.0.0", "server_port": $SS_PORT, "password": "$SS_PASSWORD", "method": "$SS_METHOD", "timeout": 300, "fast_open": true, "workers": 1, "prefer_ipv6": false, "no_delay": true, "reuse_port": true } EOF # 创建客户端配置示例 cat > "$CONFIG_PATH/client_config.json" << EOF { "server": "$SERVER_IP", "server_port": $SS_PORT, "local_address": "127.0.0.1", "local_port": 1080, "password": "$SS_PASSWORD", "method": "$SS_METHOD", "timeout": 300, "fast_open": true } EOF if [[ -f "$CONFIG_PATH/config.json" ]]; then log_info "配置文件创建成功" else log_error "配置文件创建失败" return 1 fi return 0 } # 配置防火墙 configure_firewall() { log_info "配置防火墙" # 检测和关闭旧端口 local old_ports=() # 从备份中查找旧端口 if [[ -n "$CONFIG_BACKUP" && -f "$CONFIG_BACKUP/config.json" ]]; then log_info "检测旧配置中的端口" if command -v jq &>/dev/null; then local detected_port=$(jq '.server_port' "$CONFIG_BACKUP/config.json" 2>/dev/null) if [[ "$detected_port" != "null" && -n "$detected_port" ]]; then old_ports+=("$detected_port") log_info "检测到旧端口: $detected_port" fi else local detected_port=$(grep -o '"server_port": [0-9]*' "$CONFIG_BACKUP/config.json" | awk '{print $2}') if [[ -n "$detected_port" ]]; then old_ports+=("$detected_port") log_info "检测到旧端口: $detected_port" fi fi fi # 检查是否安装了 ufw if command -v ufw &>/dev/null; then # 检查ufw是否启用 local ufw_status=$(ufw status | grep -o "Status: active" 2>/dev/null) if [[ -z "$ufw_status" ]]; then log_warn "UFW 防火墙未启用,可能需要手动配置防火墙规则" log_info "您可以运行 'sudo ufw enable' 启用 UFW 防火墙" return 0 fi # 关闭旧端口 if [[ ${#old_ports[@]} -gt 0 ]]; then log_info "开始关闭旧端口" for port in "${old_ports[@]}"; do if [[ "$port" -eq "$SS_PORT" ]]; then continue # 跳过当前端口 fi echo -n "关闭 UFW 防火墙端口 $port... " if ufw delete allow "$port" &>/dev/null; then echo -e "${GREEN}完成${NC}" else echo -e "${RED}失败${NC}" fi done fi # 开放新端口 echo -n "配置 UFW 防火墙开放端口 $SS_PORT... " if ufw allow "$SS_PORT" &>/dev/null; then echo -e "${GREEN}完成${NC}" log_info "已在 UFW 防火墙开放端口: $SS_PORT" else echo -e "${RED}失败${NC}" log_warn "无法开放端口 $SS_PORT" fi else log_warn "未检测到 UFW 防火墙,跳过防火墙配置" fi return 0 } # 生成客户端信息 generate_client_info() { log_info "生成客户端信息" # 确保IP地址已获取 if [[ -z "$SERVER_IP" ]]; then get_server_ip fi # 生成 Shadowsocks URI local userinfo="${SS_METHOD}:${SS_PASSWORD}" local userinfo_encoded=$(echo -n "$userinfo" | base64 -w 0) local share_uri="ss://${userinfo_encoded}@${SERVER_IP}:${SS_PORT}#Shadowsocks-Server" # 保存客户端信息 cat > /root/shadowsocks_info.txt << EOF ========================= Shadowsocks 配置信息 ========================= 服务器地址: ${SERVER_IP} 端口: ${SS_PORT} 密码: ${SS_PASSWORD} 加密方法: ${SS_METHOD} ================================================================== 分享链接 (SIP002 格式): ${share_uri} 二维码链接: https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=${share_uri} ================================================================== 客户端配置文件: ${CONFIG_PATH}/client_config.json 支持的客户端: - Android: shadowsocks-android - Windows: shadowsocks-windows - macOS: ShadowsocksX-NG - iOS: Shadowrocket, Quantumult - Linux: shadowsocks-libev ================================================================== 服务控制: 启动: systemctl start shadowsocks-libev 停止: systemctl stop shadowsocks-libev 重启: systemctl restart shadowsocks-libev 状态: systemctl status shadowsocks-libev 配置文件: ${CONFIG_PATH}/config.json 日志文件: /var/log/shadowsocks/shadowsocks.log ================================================================== EOF log_info "客户端信息已保存到 /root/shadowsocks_info.txt" # 打印信息 cat /root/shadowsocks_info.txt return 0 } # 创建系统服务 create_service() { log_info "创建 Shadowsocks 系统服务" # 检查并清理现有服务 if [[ -f /etc/systemd/system/shadowsocks-libev.service ]]; then log_info "检测到现有服务文件,清理现有服务" systemctl stop shadowsocks-libev &>/dev/null systemctl disable shadowsocks-libev &>/dev/null # 确保进程完全停止 pkill -f ss-server &>/dev/null sleep 2 # 删除旧服务文件 rm -f /etc/systemd/system/shadowsocks-libev.service systemctl daemon-reload log_info "现有服务已清理" fi # 创建服务文件 cat > /etc/systemd/system/shadowsocks-libev.service << EOF [Unit] Description=Shadowsocks-libev Default Server Service Documentation=man:shadowsocks-libev(8) After=network-online.target [Service] Type=simple User=root LimitNOFILE=32768 ExecStart=/usr/bin/ss-server -c $CONFIG_PATH/config.json -u -v ExecReload=/bin/kill -s HUP \$MAINPID ExecStop=/bin/kill -s TERM \$MAINPID TimeoutStopSec=10 KillMode=mixed Restart=on-failure RestartSec=5s [Install] WantedBy=multi-user.target EOF # 重新加载 systemd 配置并启用服务 systemctl daemon-reload echo -n "启用 Shadowsocks 服务... " if systemctl enable shadowsocks-libev &>/dev/null; then echo -e "${GREEN}成功${NC}" else echo -e "${RED}失败${NC}" log_error "无法启用 Shadowsocks 服务" return 1 fi echo -n "启动 Shadowsocks 服务... " if systemctl start shadowsocks-libev; then echo -e "${GREEN}成功${NC}" else echo -e "${RED}失败${NC}" log_error "无法启动 Shadowsocks 服务" return 1 fi # 等待服务启动并验证配置 echo -n "验证服务配置... " sleep 3 # 检查服务是否真正运行 if systemctl is-active shadowsocks-libev &>/dev/null; then echo -e "${GREEN}服务运行正常${NC}" # 验证端口监听 local config_port="" if command -v jq &>/dev/null; then config_port=$(jq -r '.server_port' "$CONFIG_PATH/config.json" 2>/dev/null) else config_port=$(grep -o '"server_port": [0-9]*' "$CONFIG_PATH/config.json" | awk '{print $2}' 2>/dev/null) fi if [[ -n "$config_port" ]]; then local retry_count=0 while [[ $retry_count -lt 10 ]]; do if command -v netstat &>/dev/null; then if netstat -tuln | grep -q ":$config_port "; then log_info "端口 $config_port 监听正常" break fi elif command -v ss &>/dev/null; then if ss -tuln | grep -q ":$config_port "; then log_info "端口 $config_port 监听正常" break fi fi sleep 1 retry_count=$((retry_count + 1)) done if [[ $retry_count -eq 10 ]]; then log_warn "警告: 端口 $config_port 可能未正确监听,请检查配置" fi fi else echo -e "${RED}服务启动异常${NC}" log_error "服务启动后状态异常,请检查日志" systemctl status shadowsocks-libev --no-pager -l return 1 fi return 0 } # 安装完整流程 install_shadowsocks() { clear echo "==================================================" echo -e "${GREEN}开始安装 Shadowsocks${NC}" echo "==================================================" # 检查是否为 root check_root # 检查系统环境 check_system # 备份现有配置 backup_config # 安装依赖 install_dependencies || { log_error "安装依赖失败,退出安装" return 1 } # 安装 shadowsocks-libev install_shadowsocks_libev || { log_error "安装 shadowsocks-libev 失败,退出安装" return 1 } # 配置 Shadowsocks configure_shadowsocks || { log_error "配置 Shadowsocks 失败,退出安装" return 1 } # 创建系统服务 create_service || { log_error "创建系统服务失败,但会继续安装过程" } # 配置防火墙 configure_firewall # 生成客户端信息 generate_client_info echo "" echo "==================================================" echo -e "${GREEN}Shadowsocks 安装完成!${NC}" echo "==================================================" # 最终验证 echo -e "\n${BLUE}最终验证结果:${NC}" # 检查服务状态 if systemctl is-active shadowsocks-libev &>/dev/null; then echo -e "服务状态: ${GREEN}运行中${NC}" else echo -e "服务状态: ${RED}未运行${NC}" fi # 检查端口监听 if [[ -f "$CONFIG_PATH/config.json" ]]; then local current_port="" if command -v jq &>/dev/null; then current_port=$(jq -r '.server_port' "$CONFIG_PATH/config.json" 2>/dev/null) else current_port=$(grep -o '"server_port": [0-9]*' "$CONFIG_PATH/config.json" | awk '{print $2}' 2>/dev/null) fi if [[ -n "$current_port" ]]; then if command -v netstat &>/dev/null; then if netstat -tuln | grep -q ":$current_port "; then echo -e "端口状态: ${GREEN}$current_port 正常监听${NC}" else echo -e "端口状态: ${RED}$current_port 未监听${NC}" fi elif command -v ss &>/dev/null; then if ss -tuln | grep -q ":$current_port "; then echo -e "端口状态: ${GREEN}$current_port 正常监听${NC}" else echo -e "端口状态: ${RED}$current_port 未监听${NC}" fi fi fi fi echo -e "\n${YELLOW}重要提醒:${NC}" echo "1. 客户端信息已保存到 /root/shadowsocks_info.txt" echo "2. 如果使用云服务器,请在控制台开放对应端口" echo "3. 可以运行脚本选择'4'查看详细状态" read -rp "按回车键返回主菜单..." temp show_menu } # 停止 Shadowsocks 服务 stop_shadowsocks_service() { log_info "停止 Shadowsocks 服务" if systemctl is-active shadowsocks-libev &>/dev/null; then echo -n "正在停止 Shadowsocks 服务... " if systemctl stop shadowsocks-libev &>/dev/null; then echo -e "${GREEN}成功${NC}" else echo -e "${RED}失败${NC}" log_warn "无法停止 Shadowsocks 服务,将尝试继续卸载" fi else log_info "Shadowsocks 服务未运行" fi echo -n "禁用 Shadowsocks 服务自启动... " if systemctl disable shadowsocks-libev &>/dev/null; then echo -e "${GREEN}成功${NC}" else echo -e "${YELLOW}失败${NC}" log_warn "无法禁用 Shadowsocks 服务自启动" fi } # 关闭防火墙端口 close_firewall_port() { log_info "尝试关闭之前开放的防火墙端口" # 检查是否安装了 ufw if ! command -v ufw &>/dev/null; then log_warn "未检测到 UFW 防火墙,跳过防火墙配置关闭" return 0 fi # 尝试从配置文件中读取端口 local ports=() if [[ -f "$CONFIG_PATH/config.json" ]]; then if command -v jq &>/dev/null; then local port=$(jq '.server_port' "$CONFIG_PATH/config.json" 2>/dev/null) if [[ "$port" != "null" && -n "$port" ]]; then ports+=("$port") fi else local port=$(grep -o '"server_port": [0-9]*' "$CONFIG_PATH/config.json" | awk '{print $2}') if [[ -n "$port" ]]; then ports+=("$port") fi fi fi # 如果找到了端口,关闭防火墙规则 if [[ ${#ports[@]} -gt 0 ]]; then for port in "${ports[@]}"; do echo -n "关闭 UFW 防火墙端口 $port... " if ufw delete allow "$port" &>/dev/null; then echo -e "${GREEN}完成${NC}" else echo -e "${RED}失败${NC}" fi done fi } # 删除 Shadowsocks 文件 remove_shadowsocks_files() { log_info "删除 Shadowsocks 文件" # 删除配置目录 echo -n "删除配置目录... " if [[ -d "$CONFIG_PATH" ]]; then if rm -rf "$CONFIG_PATH"; then echo -e "${GREEN}成功${NC}" else echo -e "${RED}失败${NC}" fi else echo -e "${YELLOW}配置目录不存在${NC}" fi # 删除日志目录 echo -n "删除日志目录... " if [[ -d "$LOG_PATH" ]]; then if rm -rf "$LOG_PATH"; then echo -e "${GREEN}成功${NC}" else echo -e "${RED}失败${NC}" fi else echo -e "${YELLOW}日志目录不存在${NC}" fi # 删除服务文件 echo -n "删除服务文件... " if rm -f /etc/systemd/system/shadowsocks-libev.service; then echo -e "${GREEN}成功${NC}" systemctl daemon-reload else echo -e "${YELLOW}服务文件不存在${NC}" fi # 卸载 shadowsocks-libev 软件包 echo -n "卸载 shadowsocks-libev... " if apt-get remove -y shadowsocks-libev &>/dev/null; then echo -e "${GREEN}成功${NC}" else echo -e "${YELLOW}卸载失败或软件包未安装${NC}" fi return 0 } # 完整卸载流程 uninstall_shadowsocks() { clear echo "==================================================" echo -e "${RED}开始卸载 Shadowsocks${NC}" echo "==================================================" # 确认卸载 echo -e "${YELLOW}警告: 这将卸载 Shadowsocks 并删除相关文件${NC}" read -rp "是否继续? [y/N] " confirm if [[ ! "$confirm" =~ ^[yY]$ ]]; then log_info "卸载已取消" read -rp "按回车键返回主菜单..." temp show_menu return 0 fi # 检查 root 权限 check_root # 备份配置 backup_config # 停止服务 stop_shadowsocks_service # 关闭防火墙端口 close_firewall_port # 删除文件 remove_shadowsocks_files echo "" log_info "Shadowsocks 卸载完成" read -rp "按回车键返回主菜单..." temp show_menu } # 检查 Shadowsocks 状态 check_status() { clear echo "==================================================" echo -e "${BLUE}Shadowsocks 状态检查${NC}" echo "==================================================" # 检查是否安装 if ! command -v ss-server &>/dev/null; then echo -e "${RED}Shadowsocks 未安装${NC}" read -rp "按回车键返回主菜单..." temp show_menu return 0 fi # 检查版本 echo -n "Shadowsocks 版本: " ss-server -h 2>&1 | grep -o 'shadowsocks-libev [0-9]\+\.[0-9]\+\.[0-9]\+' || echo "shadowsocks-libev $(dpkg -l shadowsocks-libev 2>/dev/null | grep '^ii' | awk '{print $3}' || echo '未知版本')" # 检查服务状态 echo -n "服务状态: " if systemctl is-active shadowsocks-libev &>/dev/null; then echo -e "${GREEN}运行中${NC}" else echo -e "${RED}未运行${NC}" fi echo -n "自启动状态: " if systemctl is-enabled shadowsocks-libev &>/dev/null; then echo -e "${GREEN}已启用${NC}" else echo -e "${RED}未启用${NC}" fi # 检查端口 if [[ -f "$CONFIG_PATH/config.json" ]]; then local current_port="" if command -v jq &>/dev/null; then current_port=$(jq '.server_port' "$CONFIG_PATH/config.json" 2>/dev/null) else current_port=$(grep -o '"server_port": [0-9]*' "$CONFIG_PATH/config.json" | awk '{print $2}') fi if [[ -n "$current_port" && "$current_port" != "null" ]]; then echo -n "端口 $current_port 状态: " if command -v netstat &>/dev/null; then if netstat -tuln | grep -q ":$current_port "; then echo -e "${GREEN}已开放${NC}" else echo -e "${RED}未开放${NC}" fi elif command -v ss &>/dev/null; then if ss -tuln | grep -q ":$current_port "; then echo -e "${GREEN}已开放${NC}" else echo -e "${RED}未开放${NC}" fi else echo -e "${YELLOW}无法检查${NC}" fi fi fi echo -e "\n最近的日志:" if systemctl status shadowsocks-libev &>/dev/null; then systemctl status shadowsocks-libev --no-pager -l else echo "无法获取服务日志" fi read -rp "按回车键返回主菜单..." temp show_menu } # 显示配置信息 show_config() { clear echo "==================================================" echo -e "${CYAN}Shadowsocks 配置信息${NC}" echo "==================================================" # 检查是否已安装 if ! command -v ss-server &>/dev/null; then echo -e "${RED}Shadowsocks 未安装${NC}" read -rp "按回车键返回主菜单..." temp show_menu return 0 fi # 显示配置文件内容 if [[ -f "$CONFIG_PATH/config.json" ]]; then echo "服务器配置:" if command -v jq &>/dev/null; then jq . "$CONFIG_PATH/config.json" else cat "$CONFIG_PATH/config.json" fi else echo -e "${RED}找不到服务器配置文件${NC}" fi echo -e "\n" # 显示客户端信息 if [[ -f "/root/shadowsocks_info.txt" ]]; then echo "客户端信息:" cat /root/shadowsocks_info.txt else echo -e "${RED}找不到客户端信息文件${NC}" fi read -rp "按回车键返回主菜单..." temp show_menu } # 重启 Shadowsocks 服务 restart_service() { clear echo "==================================================" echo -e "${GREEN}重启 Shadowsocks 服务${NC}" echo "==================================================" # 检查是否已安装 if ! command -v ss-server &>/dev/null; then echo -e "${RED}Shadowsocks 未安装${NC}" read -rp "按回车键返回主菜单..." temp show_menu return 0 fi echo -n "重启 Shadowsocks 服务... " if systemctl restart shadowsocks-libev; then echo -e "${GREEN}成功${NC}" log_info "Shadowsocks 服务已重启" else echo -e "${RED}失败${NC}" log_error "无法重启 Shadowsocks 服务" fi # 等待服务启动 echo -n "等待服务启动... " sleep 3 echo -e "${GREEN}完成${NC}" # 检查服务状态 echo -n "Shadowsocks 服务状态: " if systemctl is-active shadowsocks-libev &>/dev/null; then echo -e "${GREEN}运行中${NC}" else echo -e "${RED}未运行${NC}" fi # 验证端口监听 if [[ -f "$CONFIG_PATH/config.json" ]]; then local current_port="" if command -v jq &>/dev/null; then current_port=$(jq -r '.server_port' "$CONFIG_PATH/config.json" 2>/dev/null) else current_port=$(grep -o '"server_port": [0-9]*' "$CONFIG_PATH/config.json" | awk '{print $2}' 2>/dev/null) fi if [[ -n "$current_port" ]]; then echo -n "端口 $current_port 监听状态: " if command -v netstat &>/dev/null; then if netstat -tuln | grep -q ":$current_port "; then echo -e "${GREEN}正常${NC}" else echo -e "${RED}未监听${NC}" fi elif command -v ss &>/dev/null; then if ss -tuln | grep -q ":$current_port "; then echo -e "${GREEN}正常${NC}" else echo -e "${RED}未监听${NC}" fi fi fi fi read -rp "按回车键返回主菜单..." temp show_menu } # 修改配置 modify_config() { clear echo "==================================================" echo -e "${YELLOW}修改 Shadowsocks 配置${NC}" echo "==================================================" # 检查是否已安装 if ! command -v ss-server &>/dev/null; then echo -e "${RED}Shadowsocks 未安装${NC}" read -rp "按回车键返回主菜单..." temp show_menu return 0 fi # 读取当前配置 if [[ -f "$CONFIG_PATH/config.json" ]]; then if command -v jq &>/dev/null; then SS_PORT=$(jq -r '.server_port' "$CONFIG_PATH/config.json") SS_PASSWORD=$(jq -r '.password' "$CONFIG_PATH/config.json") SS_METHOD=$(jq -r '.method' "$CONFIG_PATH/config.json") else SS_PORT=$(grep -o '"server_port": [0-9]*' "$CONFIG_PATH/config.json" | awk '{print $2}') SS_PASSWORD=$(grep -o '"password": "[^"]*"' "$CONFIG_PATH/config.json" | cut -d'"' -f4) SS_METHOD=$(grep -o '"method": "[^"]*"' "$CONFIG_PATH/config.json" | cut -d'"' -f4) fi fi echo "当前配置:" echo "端口: $SS_PORT" echo "密码: $SS_PASSWORD" echo "加密方法: $SS_METHOD" echo "" echo "1) 修改端口" echo "2) 修改密码" echo "3) 修改加密方法" echo "4) 重新生成所有配置" echo "0) 返回主菜单" echo "" read -rp "请选择 [0-4]: " modify_choice local config_changed=false case $modify_choice in 1) read -rp "请输入新端口 (当前: $SS_PORT): " new_port if [[ "$new_port" =~ ^[0-9]+$ ]] && [[ "$new_port" -ge 1 ]] && [[ "$new_port" -le 65535 ]]; then SS_PORT="$new_port" config_changed=true else log_error "无效端口" fi ;; 2) read -rp "请输入新密码 (当前: $SS_PASSWORD): " new_password if [[ ${#new_password} -ge 8 ]]; then SS_PASSWORD="$new_password" config_changed=true else log_error "密码至少需要8位" fi ;; 3) echo "选择新的加密方法:" echo "1) chacha20-ietf-poly1305" echo "2) aes-256-gcm" echo "3) aes-192-gcm" echo "4) aes-128-gcm (默认)" read -rp "请选择 [1-4, 默认4]: " method_choice case $method_choice in 1) SS_METHOD="chacha20-ietf-poly1305"; config_changed=true ;; 2) SS_METHOD="aes-256-gcm"; config_changed=true ;; 3) SS_METHOD="aes-192-gcm"; config_changed=true ;; 4) SS_METHOD="aes-128-gcm"; config_changed=true ;; "") SS_METHOD="aes-128-gcm"; config_changed=true ;; # 默认选择 *) log_error "无效选择" ;; esac ;; 4) SS_PORT="" SS_PASSWORD="" configure_shadowsocks create_service configure_firewall generate_client_info log_info "配置已重新生成" read -rp "按回车键返回主菜单..." temp show_menu return 0 ;; 0) show_menu return 0 ;; *) log_error "无效选择" read -rp "按回车键重试..." temp modify_config return 0 ;; esac if [[ "$config_changed" == true ]]; then # 更新配置文件 cat > "$CONFIG_PATH/config.json" << EOF { "server": "0.0.0.0", "server_port": $SS_PORT, "password": "$SS_PASSWORD", "method": "$SS_METHOD", "timeout": 300, "fast_open": true, "workers": 1, "prefer_ipv6": false, "no_delay": true, "reuse_port": true } EOF # 重启服务 systemctl restart shadowsocks-libev # 重新配置防火墙 configure_firewall # 重新生成客户端信息 generate_client_info log_info "配置已更新并重启服务" fi read -rp "按回车键返回主菜单..." temp show_menu } # 更新 Shadowsocks update_shadowsocks() { clear echo "==================================================" echo -e "${YELLOW}更新 Shadowsocks${NC}" echo "==================================================" # 检查是否已安装 if ! command -v ss-server &>/dev/null; then echo -e "${RED}Shadowsocks 未安装,请先安装${NC}" read -rp "按回车键返回主菜单..." temp show_menu return 0 fi # 备份配置 backup_config # 停止服务 echo -n "停止 Shadowsocks 服务... " if systemctl stop shadowsocks-libev &>/dev/null; then echo -e "${GREEN}成功${NC}" else echo -e "${RED}失败${NC}" log_warn "无法停止 Shadowsocks 服务" fi # 更新软件包 apt_progress "apt-get update" "更新软件包列表" apt_progress "apt-get upgrade -y shadowsocks-libev" "更新 shadowsocks-libev" # 启动服务 echo -n "启动 Shadowsocks 服务... " if systemctl start shadowsocks-libev; then echo -e "${GREEN}成功${NC}" else echo -e "${RED}失败${NC}" log_error "启动 Shadowsocks 服务失败" fi log_info "Shadowsocks 更新完成" read -rp "按回车键返回主菜单..." temp show_menu } # 主函数 main() { # 创建日志目录 mkdir -p "$(dirname "$LOG_FILE")" # 处理命令行参数 if [[ $# -gt 0 ]]; then case "$1" in -h|--help) show_help exit 0 ;; -i|--install) check_root install_shadowsocks exit 0 ;; -u|--uninstall) check_root uninstall_shadowsocks exit 0 ;; -s|--status) check_root check_status exit 0 ;; -up|--update) check_root update_shadowsocks exit 0 ;; *) log_error "未知参数: $1" show_help exit 1 ;; esac fi # 无参数则显示菜单 check_root show_menu } # 执行主函数 main "$@"