Files
dock/01
2025-11-05 23:00:19 +08:00

703 lines
21 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# 加强版服务器控制器脚本
# 支持多客户端管理、日志记录、安全控制
SERVER_PORT=25555
LOG_FILE="/var/log/controller_server.log"
CLIENTS_FILE="/var/lib/controller_clients.txt"
SCRIPT_DIR="/opt/controller_scripts"
BACKUP_DIR="/var/backup/controller"
CONFIG_FILE="/etc/controller_server.conf"
PID_FILE="/var/run/controller_server.pid"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m'
# 初始化配置
init_config() {
mkdir -p "$(dirname "$LOG_FILE")"
mkdir -p "$(dirname "$CLIENTS_FILE")"
mkdir -p "$SCRIPT_DIR"
mkdir -p "$BACKUP_DIR"
# 创建配置文件
if [[ ! -f "$CONFIG_FILE" ]]; then
cat > "$CONFIG_FILE" << EOF
# 服务器控制器配置
SERVER_PORT=$SERVER_PORT
LOG_FILE="$LOG_FILE"
CLIENTS_FILE="$CLIENTS_FILE"
SCRIPT_DIR="$SCRIPT_DIR"
BACKUP_DIR="$BACKUP_DIR"
PID_FILE="$PID_FILE"
MAX_CLIENTS=1000
HEARTBEAT_TIMEOUT=300
ALLOWED_IPS="0.0.0.0/0"
ENABLE_LOGGING=true
EOF
fi
source "$CONFIG_FILE"
# 创建示例脚本
create_sample_scripts
create_management_scripts
touch "$LOG_FILE"
touch "$CLIENTS_FILE"
chmod 600 "$CLIENTS_FILE"
}
log() {
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
if [[ "$ENABLE_LOGGING" == "true" ]]; then
echo -e "[$timestamp] $1" | tee -a "$LOG_FILE"
else
echo -e "[$timestamp] $1"
fi
}
print_color() {
echo -e "${2}${1}${NC}"
}
print_banner() {
clear
echo
print_color "╔══════════════════════════════════════════════════════════════╗" "$CYAN"
print_color "║ 加强版服务器控制器 v2.0 ║" "$BLUE"
print_color "║ Enhanced Server Controller v2.0 ║" "$BLUE"
print_color "╠══════════════════════════════════════════════════════════════╣" "$CYAN"
print_color "║ 端口: $SERVER_PORT | 客户端数: $(get_client_count) | 状态: $(server_status)" "$GREEN"
print_color "╚══════════════════════════════════════════════════════════════╝" "$CYAN"
echo
}
# 检查依赖
check_dependencies() {
local deps=("nc" "awk" "grep" "sed")
local missing=()
for dep in "${deps[@]}"; do
if ! command -v "$dep" &> /dev/null; then
missing+=("$dep")
fi
done
if [[ ${#missing[@]} -gt 0 ]]; then
print_color "缺少依赖: ${missing[*]}" "$RED"
print_color "正在安装..." "$YELLOW"
if command -v apt-get &> /dev/null; then
apt-get update && apt-get install -y netcat-traditional awk grep sed
elif command -v yum &> /dev/null; then
yum install -y nc awk grep sed
elif command -v dnf &> /dev/null; then
dnf install -y nc awk grep sed
elif command -v apk &> /dev/null; then
apk add netcat-openbsd awk grep sed
fi
fi
}
# 创建管理脚本
create_management_scripts() {
# 批量更新脚本
cat > "$SCRIPT_DIR/batch_update.sh" << 'EOF'
#!/bin/bash
echo "开始批量更新所有客户端..."
for client in $(grep -oP '^[^|]+' /var/lib/controller_clients.txt); do
echo "更新客户端: $client"
echo "COMMAND:apt-get update && apt-get upgrade -y" | nc -w 3 $(get_client_ip $client) 5556
done
echo "批量更新完成"
EOF
# 系统信息收集脚本
cat > "$SCRIPT_DIR/collect_system_info.sh" << 'EOF'
#!/bin/bash
echo "收集所有客户端系统信息..."
while IFS='|' read -r serial ip hostname system last_seen; do
if [[ -n "$serial" ]]; then
echo "=== $hostname ($serial) ==="
echo "COMMAND:uname -a; free -h; df -h" | nc -w 3 "$ip" 5556
echo "------------------------"
fi
done < /var/lib/controller_clients.txt
EOF
# 网络诊断脚本
cat > "$SCRIPT_DIR/network_diagnosis.sh" << 'EOF'
#!/bin/bash
echo "网络诊断..."
while IFS='|' read -r serial ip hostname system last_seen; do
if [[ -n "$serial" ]]; then
echo "检查 $hostname 网络..."
echo "COMMAND:ip addr show; ping -c 2 8.8.8.8" | nc -w 3 "$ip" 5556
fi
done < /var/lib/controller_clients.txt
EOF
chmod +x "$SCRIPT_DIR"/*.sh
}
create_sample_scripts() {
# 基础管理脚本
cat > "$SCRIPT_DIR/shutdown.sh" << 'EOF'
#!/bin/bash
echo "执行关机操作..."
shutdown -h now
EOF
cat > "$SCRIPT_DIR/reboot.sh" << 'EOF'
#!/bin/bash
echo "执行重启操作..."
reboot
EOF
cat > "$SCRIPT_DIR/restart_services.sh" << 'EOF'
#!/bin/bash
echo "重启系统服务..."
systemctl restart networking 2>/dev/null || systemctl restart network 2>/dev/null
systemctl restart ssh 2>/dev/null || systemctl restart sshd 2>/dev/null
EOF
# 监控脚本
cat > "$SCRIPT_DIR/monitor_system.sh" << 'EOF'
#!/bin/bash
echo "=== 系统监控 ==="
echo "主机名: $(hostname)"
echo "上线时间: $(uptime)"
echo "内存使用:"
free -h
echo "磁盘使用:"
df -h
echo "CPU使用:"
top -bn1 | head -10
EOF
# 安全脚本
cat > "$SCRIPT_DIR/security_check.sh" << 'EOF'
#!/bin/bash
echo "=== 安全检查 ==="
echo "登录用户:"
who
echo "失败登录:"
lastb | head -10
echo "SSH连接:"
netstat -tlnp | grep ssh
EOF
chmod +x "$SCRIPT_DIR"/*.sh
}
# 服务器状态
server_status() {
if is_server_running; then
echo -e "${GREEN}运行中${NC}"
else
echo -e "${RED}未运行${NC}"
fi
}
is_server_running() {
if [[ -f "$PID_FILE" ]]; then
local pid=$(cat "$PID_FILE")
if kill -0 "$pid" 2>/dev/null; then
return 0
else
rm -f "$PID_FILE"
fi
fi
return 1
}
# 获取客户端数量
get_client_count() {
if [[ -f "$CLIENTS_FILE" ]]; then
grep -c . "$CLIENTS_FILE" 2>/dev/null || echo "0"
else
echo "0"
fi
}
# 获取客户端IP
get_client_ip() {
local serial=$1
grep "^$serial|" "$CLIENTS_FILE" | cut -d'|' -f2
}
# 清理过期客户端
cleanup_expired_clients() {
local current_time=$(date +%s)
local temp_file=$(mktemp)
while IFS='|' read -r serial ip hostname system last_seen; do
if [[ -n "$last_seen" ]]; then
local client_time=$(date -d "$last_seen" +%s 2>/dev/null || echo "0")
local time_diff=$((current_time - client_time))
if [[ $time_diff -lt $HEARTBEAT_TIMEOUT ]]; then
echo "$serial|$ip|$hostname|$system|$last_seen" >> "$temp_file"
else
log "清理过期客户端: $serial ($hostname)"
fi
fi
done < "$CLIENTS_FILE"
mv "$temp_file" "$CLIENTS_FILE" 2>/dev/null
}
# 备份数据
backup_data() {
local backup_file="$BACKUP_DIR/backup_$(date +%Y%m%d_%H%M%S).tar.gz"
tar -czf "$backup_file" "$CLIENTS_FILE" "$LOG_FILE" "$SCRIPT_DIR" 2>/dev/null
log "数据已备份到: $backup_file"
}
# 显示客户端列表
show_clients() {
cleanup_expired_clients
local count=$(get_client_count)
print_color "已连接客户端: $count" "$BLUE"
if [[ $count -eq 0 ]]; then
print_color "没有客户端连接" "$YELLOW"
return
fi
print_color "┌────────────┬───────────────┬──────────────────┬─────────────────┬─────────────────────┐" "$CYAN"
print_color "│ 序列号 │ IP地址 │ 主机名 │ 系统 │ 最后在线 │" "$CYAN"
print_color "├────────────┼───────────────┼──────────────────┼─────────────────┼─────────────────────┤" "$CYAN"
while IFS='|' read -r serial ip hostname system last_seen; do
if [[ -n "$serial" ]]; then
printf "${GREEN}%-10s${NC}${YELLOW}%-13s${NC}${BLUE}%-16s${NC}${PURPLE}%-15s${NC}${GREEN}%-19s${NC} │\n" \
"$serial" "$ip" "$hostname" "$system" "$last_seen"
fi
done < "$CLIENTS_FILE"
print_color "└────────────┴───────────────┴──────────────────┴─────────────────┴─────────────────────┘" "$CYAN"
}
# 向客户端发送命令
send_command() {
local serial=$1
shift
local command="$*"
if [[ -z "$serial" || -z "$command" ]]; then
print_color "用法: send <序列号> <命令>" "$RED"
return
fi
local client_info=$(grep "^$serial|" "$CLIENTS_FILE")
if [[ -z "$client_info" ]]; then
print_color "错误: 未找到序列号 $serial 的客户端" "$RED"
return
fi
IFS='|' read -r serial ip hostname system last_seen <<< "$client_info"
print_color "向客户端 $serial 发送命令..." "$GREEN"
print_color "客户端: $hostname ($ip)" "$BLUE"
print_color "命令: $command" "$YELLOW"
# 发送命令到客户端
echo "COMMAND:$command" | nc -w 5 "$ip" 5556
if [[ $? -eq 0 ]]; then
log "命令发送成功: $serial -> $command"
print_color "命令发送成功!" "$GREEN"
else
log "命令发送失败: $serial -> $command"
print_color "命令发送失败!" "$RED"
fi
}
# 广播命令到所有客户端
broadcast_command() {
local command="$*"
if [[ -z "$command" ]]; then
print_color "用法: broadcast <命令>" "$RED"
return
fi
local count=0
print_color "向所有客户端广播命令..." "$YELLOW"
print_color "命令: $command" "$PURPLE"
while IFS='|' read -r serial ip hostname system last_seen; do
if [[ -n "$serial" ]]; then
echo "$serial 发送命令..."
echo "COMMAND:$command" | nc -w 3 "$ip" 5556 &
count=$((count + 1))
fi
done < "$CLIENTS_FILE"
wait
log "广播命令完成: $command -> $count 个客户端"
print_color "广播完成! 共发送给 $count 个客户端" "$GREEN"
}
# 执行脚本
execute_script() {
local serial=$1
local script_name=$2
if [[ -z "$serial" || -z "$script_name" ]]; then
print_color "用法: script <序列号> <脚本名>" "$RED"
show_available_scripts
return
fi
local script_path="$SCRIPT_DIR/$script_name"
if [[ ! -f "$script_path" ]]; then
print_color "错误: 脚本 $script_name 不存在" "$RED"
show_available_scripts
return
fi
local client_info=$(grep "^$serial|" "$CLIENTS_FILE")
if [[ -z "$client_info" ]]; then
print_color "错误: 未找到序列号 $serial 的客户端" "$RED"
return
fi
IFS='|' read -r serial ip hostname system last_seen <<< "$client_info"
print_color "向客户端 $serial 发送脚本..." "$GREEN"
print_color "客户端: $hostname ($ip)" "$BLUE"
print_color "脚本: $script_name" "$YELLOW"
# 发送脚本执行命令
echo "SCRIPT:$script_name" | nc -w 5 "$ip" 5556
if [[ $? -eq 0 ]]; then
log "脚本发送成功: $serial -> $script_name"
print_color "脚本发送成功!" "$GREEN"
else
log "脚本发送失败: $serial -> $script_name"
print_color "脚本发送失败!" "$RED"
fi
}
# 显示可用脚本
show_available_scripts() {
print_color "可用脚本:" "$BLUE"
echo
print_color "系统管理:" "$CYAN"
ls "$SCRIPT_DIR"/*.sh 2>/dev/null | xargs -n 1 basename | while read script; do
print_color " 📜 $script" "$GREEN"
done || print_color " 无可用脚本" "$YELLOW"
}
# 批量执行脚本
batch_execute_script() {
local script_name=$1
if [[ -z "$script_name" ]]; then
print_color "用法: batch <脚本名>" "$RED"
show_available_scripts
return
fi
local script_path="$SCRIPT_DIR/$script_name"
if [[ ! -f "$script_path" ]]; then
print_color "错误: 脚本 $script_name 不存在" "$RED"
return
fi
local count=0
print_color "批量执行脚本: $script_name" "$YELLOW"
while IFS='|' read -r serial ip hostname system last_seen; do
if [[ -n "$serial" ]]; then
echo "$serial 发送脚本..."
echo "SCRIPT:$script_name" | nc -w 3 "$ip" 5556 &
count=$((count + 1))
fi
done < "$CLIENTS_FILE"
wait
log "批量执行完成: $script_name -> $count 个客户端"
print_color "批量执行完成! 共发送给 $count 个客户端" "$GREEN"
}
# 查看客户端详情
show_client_detail() {
local serial=$1
if [[ -z "$serial" ]]; then
print_color "用法: detail <序列号>" "$RED"
return
fi
local client_info=$(grep "^$serial|" "$CLIENTS_FILE")
if [[ -z "$client_info" ]]; then
print_color "错误: 未找到序列号 $serial 的客户端" "$RED"
return
fi
IFS='|' read -r serial ip hostname system last_seen <<< "$client_info"
print_color "=== 客户端详情 ===" "$BLUE"
print_color "序列号: $serial" "$GREEN"
print_color "IP地址: $ip" "$YELLOW"
print_color "主机名: $hostname" "$CYAN"
print_color "系统信息: $system" "$PURPLE"
print_color "最后在线: $last_seen" "$GREEN"
# 测试连接
print_color "连接测试..." "$BLUE"
if ping -c 1 -W 1 "$ip" &> /dev/null; then
print_color "网络连接: 正常" "$GREEN"
else
print_color "网络连接: 失败" "$RED"
fi
}
# 启动服务器
start_server() {
if is_server_running; then
print_color "服务器已经在运行 (PID: $(cat "$PID_FILE"))" "$YELLOW"
return
fi
print_color "启动服务器在端口 $SERVER_PORT ..." "$GREEN"
# 保存PID
echo $$ > "$PID_FILE"
# 设置信号处理
trap 'cleanup' INT TERM EXIT
log "服务器启动成功PID: $$"
while true; do
log "等待客户端连接..."
nc -l -p $SERVER_PORT -c '
client_ip=$(echo $SSH_CLIENT | awk "{print \$1}")
if [[ -z "$client_ip" ]]; then
client_ip="unknown"
fi
read -r data
timestamp=$(date "+%Y-%m-%d %H:%M:%S")
if echo "$data" | grep -q "HEARTBEAT|"; then
IFS="|" read -r heartbeat serial hostname system <<< "$data"
# 更新客户端信息
grep -v "^$serial|" /var/lib/controller_clients.txt > /tmp/clients.tmp 2>/dev/null
echo "$serial|$client_ip|$hostname|$system|$timestamp" >> /tmp/clients.tmp
mv /tmp/clients.tmp /var/lib/controller_clients.txt
echo "ACK:OK"
echo "客户端 $serial 已连接 - $hostname ($client_ip)"
else
echo "ACK:UNKNOWN_COMMAND"
fi
' 2>/dev/null
sleep 1
done
}
cleanup() {
log "服务器停止"
rm -f "$PID_FILE"
exit 0
}
# 停止服务器
stop_server() {
if is_server_running; then
local pid=$(cat "$PID_FILE")
print_color "停止服务器 (PID: $pid)..." "$GREEN"
kill "$pid"
sleep 2
if is_server_running; then
kill -9 "$pid"
fi
print_color "服务器已停止" "$GREEN"
else
print_color "服务器未在运行" "$YELLOW"
fi
}
# 查看服务器日志
show_log() {
if [[ -f "$LOG_FILE" ]]; then
tail -20 "$LOG_FILE"
else
print_color "日志文件不存在" "$RED"
fi
}
# 显示统计信息
show_stats() {
local total_clients=$(get_client_count)
local active_clients=0
local current_time=$(date +%s)
while IFS='|' read -r serial ip hostname system last_seen; do
if [[ -n "$last_seen" ]]; then
local client_time=$(date -d "$last_seen" +%s 2>/dev/null || echo "0")
local time_diff=$((current_time - client_time))
if [[ $time_diff -lt 600 ]]; then # 10分钟内活跃
active_clients=$((active_clients + 1))
fi
fi
done < "$CLIENTS_FILE"
print_color "=== 服务器统计 ===" "$BLUE"
print_color "总客户端数: $total_clients" "$GREEN"
print_color "活跃客户端: $active_clients" "$CYAN"
print_color "服务器运行: $(is_server_running && echo '是' || echo '否')" "$YELLOW"
print_color "启动时间: $(ps -p $(cat "$PID_FILE" 2>/dev/null) -o lstart= 2>/dev/null || echo '未知')" "$PURPLE"
}
# 显示帮助
show_help() {
print_color "可用命令:" "$BLUE"
echo
print_color "服务器管理:" "$CYAN"
echo " start - 启动服务器"
echo " stop - 停止服务器"
echo " restart - 重启服务器"
echo " status - 服务器状态"
echo " log - 查看日志"
echo " stats - 统计信息"
echo " backup - 备份数据"
print_color "客户端管理:" "$CYAN"
echo " list - 显示客户端列表"
echo " detail - 查看客户端详情"
echo " send - 发送命令到客户端"
echo " broadcast - 广播命令到所有客户端"
echo " script - 执行脚本到客户端"
echo " batch - 批量执行脚本"
print_color "脚本管理:" "$CYAN"
echo " scripts - 显示可用脚本"
print_color "系统管理:" "$CYAN"
echo " help - 显示帮助"
echo " exit - 退出"
}
# 主菜单
main_menu() {
while true; do
print_banner
echo
print_color "请选择操作:" "$BLUE"
echo
print_color "1. 启动服务器" "$GREEN"
print_color "2. 停止服务器" "$RED"
print_color "3. 客户端列表" "$CYAN"
print_color "4. 发送命令" "$YELLOW"
print_color "5. 广播命令" "$PURPLE"
print_color "6. 执行脚本" "$BLUE"
print_color "7. 批量执行" "$CYAN"
print_color "8. 客户端详情" "$GREEN"
print_color "9. 查看日志" "$YELLOW"
print_color "10. 统计信息" "$PURPLE"
print_color "11. 备份数据" "$BLUE"
print_color "12. 显示脚本" "$CYAN"
print_color "13. 帮助" "$GREEN"
print_color "0. 退出" "$RED"
echo
read -p "请输入选择 [0-13]: " choice
case $choice in
1) start_server ;;
2) stop_server ;;
3) show_clients ;;
4)
read -p "输入序列号: " serial
read -p "输入命令: " cmd
send_command "$serial" "$cmd"
;;
5)
read -p "输入广播命令: " cmd
broadcast_command "$cmd"
;;
6)
read -p "输入序列号: " serial
read -p "输入脚本名: " script
execute_script "$serial" "$script"
;;
7)
read -p "输入脚本名: " script
batch_execute_script "$script"
;;
8)
read -p "输入序列号: " serial
show_client_detail "$serial"
;;
9) show_log ;;
10) show_stats ;;
11) backup_data ;;
12) show_available_scripts ;;
13) show_help ;;
0)
print_color "再见!" "$GREEN"
exit 0
;;
*)
print_color "无效选择!" "$RED"
;;
esac
echo
read -p "按回车键继续..."
done
}
# 命令行参数处理
case "${1:-}" in
"start")
check_dependencies
init_config
start_server
;;
"stop")
stop_server
;;
"restart")
stop_server
sleep 2
check_dependencies
init_config
start_server
;;
"status")
if is_server_running; then
print_color "服务器运行中 (PID: $(cat "$PID_FILE"))" "$GREEN"
else
print_color "服务器未运行" "$RED"
fi
;;
"log")
show_log
;;
*)
check_dependencies
init_config
main_menu
;;
esac