secubox-openwrt/package/secubox/secubox-app-rustdesk/files/usr/sbin/rustdeskctl
CyberMind-FR 304ac7b9a1 feat: P2P App Store, Remote Access & Mesh Media packages
P2P App Store Emancipation:
- secubox-p2p: Package distribution via mesh peers (CGI API, RPCD, CLI)
- packages.js: LuCI view with LOCAL/PEER badges, fetch/install actions
- devstatus.js: Dev Status widget with Gitea commits, v1.0 progress tracking
- secubox-feed: sync-content command for auto-installing content packages
- ACL fix for P2P feed RPCD methods

Remote Access:
- secubox-app-rustdesk: Native hbbs/hbbr relay server from GitHub releases
- secubox-app-guacamole: LXC Debian container with guacd + Tomcat (partial)

Content Distribution:
- secubox-content-pkg: Auto-package Metablogizer/Streamlit as IPKs
- Auto-publish hooks in metablogizerctl and streamlitctl

Mesh Media:
- secubox-app-ksmbd: In-kernel SMB3 server with ksmbdctl CLI
- Pre-configured shares for Jellyfin, Lyrion, Backup

UI Consistency:
- client-guardian: Ported to sh-page-header chip layout
- auth-guardian: Ported to sh-page-header chip layout

Fixes:
- services.js: RPC expect unwrapping bug fix
- metablogizer: Chunked upload for uhttpd 64KB limit

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 00:33:53 +01:00

409 lines
9.8 KiB
Bash

#!/bin/sh
# SecuBox RustDesk Server Manager
CONFIG="rustdesk"
VERSION="1.1.15"
DOWNLOAD_URL="https://github.com/rustdesk/rustdesk-server/releases/download/${VERSION}"
DATA_PATH_DEFAULT="/srv/rustdesk"
HBBS_PID=""
HBBR_PID=""
usage() {
cat <<'USAGE'
Usage: rustdeskctl <command>
Commands:
install Download RustDesk server binaries
uninstall Remove binaries (preserves key)
status Show server status and public key
keygen Regenerate authentication key
logs [-f] Show server logs
configure-firewall Open WAN ports (21115-21117)
mesh-register Register with P2P mesh
service-run Internal: run servers via procd
service-stop Internal: stop servers
USAGE
}
# ---------- helpers ----------
require_root() { [ "$(id -u)" -eq 0 ]; }
uci_get() {
local key="$1"
local section="${2:-server}"
uci -q get ${CONFIG}.${section}.$key
}
uci_set() {
local key="$1"
local value="$2"
local section="${3:-server}"
uci set ${CONFIG}.${section}.$key="$value"
}
log_info() { echo "[INFO] $*"; logger -t rustdeskctl "$*"; }
log_error() { echo "[ERROR] $*" >&2; logger -t rustdeskctl -p err "$*"; }
ensure_dir() { [ -d "$1" ] || mkdir -p "$1"; }
defaults() {
data_path="$(uci_get data_path || echo $DATA_PATH_DEFAULT)"
id_port="$(uci_get id_port || echo 21116)"
relay_port="$(uci_get relay_port || echo 21117)"
}
detect_arch() {
case "$(uname -m)" in
aarch64) echo "arm64v8" ;;
armv7l) echo "armv7" ;;
x86_64) echo "amd64" ;;
*) echo "amd64" ;;
esac
}
# ---------- installation ----------
cmd_install() {
require_root || { log_error "Must run as root"; return 1; }
defaults
local arch=$(detect_arch)
local zip_file="/tmp/rustdesk-server.zip"
local zip_url="${DOWNLOAD_URL}/rustdesk-server-linux-${arch}.zip"
log_info "Downloading RustDesk server v${VERSION} for ${arch}..."
ensure_dir "$data_path"
cd "$data_path" || return 1
# Download
wget -q -O "$zip_file" "$zip_url" || {
log_error "Failed to download from $zip_url"
return 1
}
# Extract
unzip -o -q "$zip_file" -d "$data_path" || {
log_error "Failed to extract archive"
rm -f "$zip_file"
return 1
}
rm -f "$zip_file"
# Find and move binaries (they may be in a subdirectory)
# Check common subdirectory patterns from RustDesk releases
for subdir in arm64v8 aarch64-unknown-linux-gnu amd64 x86_64-unknown-linux-gnu armv7; do
if [ -d "$data_path/$subdir" ]; then
log_info "Moving binaries from $subdir subdirectory..."
mv "$data_path/$subdir"/* "$data_path/" 2>/dev/null
rmdir "$data_path/$subdir" 2>/dev/null
break
fi
done
# Make executable
chmod +x "$data_path/hbbs" "$data_path/hbbr" 2>/dev/null
# Verify binaries exist
if [ ! -x "$data_path/hbbs" ] || [ ! -x "$data_path/hbbr" ]; then
log_error "Binaries not found after extraction"
ls -la "$data_path"
return 1
fi
# Generate key if not exists
if [ ! -f "$data_path/id_ed25519" ]; then
log_info "Generating authentication key..."
cd "$data_path"
# Run hbbs briefly to generate key
timeout 3 ./hbbs -p "$id_port" >/dev/null 2>&1 || true
sleep 1
fi
# Store key in UCI if generated
if [ -f "$data_path/id_ed25519.pub" ]; then
local pubkey=$(cat "$data_path/id_ed25519.pub" 2>/dev/null)
uci_set key "$pubkey"
uci commit "$CONFIG"
fi
log_info "RustDesk server installed successfully"
log_info "Data directory: $data_path"
# Show key
if [ -f "$data_path/id_ed25519.pub" ]; then
echo ""
echo "Public key for client configuration:"
cat "$data_path/id_ed25519.pub"
fi
# Enable service
uci_set enabled '1'
uci commit "$CONFIG"
/etc/init.d/rustdesk enable
/etc/init.d/rustdesk start
log_info "Service enabled and started"
}
cmd_uninstall() {
require_root || { log_error "Must run as root"; return 1; }
defaults
log_info "Stopping RustDesk server..."
/etc/init.d/rustdesk stop 2>/dev/null
/etc/init.d/rustdesk disable 2>/dev/null
# Remove binaries but keep keys
rm -f "$data_path/hbbs" "$data_path/hbbr" 2>/dev/null
uci_set enabled '0'
uci commit "$CONFIG"
log_info "RustDesk binaries removed (keys preserved in $data_path)"
}
cmd_keygen() {
require_root || { log_error "Must run as root"; return 1; }
defaults
log_info "Regenerating authentication key..."
# Stop service
/etc/init.d/rustdesk stop 2>/dev/null
# Remove old keys
rm -f "$data_path/id_ed25519" "$data_path/id_ed25519.pub" 2>/dev/null
# Generate new key by running hbbs briefly
cd "$data_path"
timeout 3 ./hbbs -p "$id_port" >/dev/null 2>&1 || true
sleep 1
if [ -f "$data_path/id_ed25519.pub" ]; then
local pubkey=$(cat "$data_path/id_ed25519.pub" 2>/dev/null)
uci_set key "$pubkey"
uci commit "$CONFIG"
log_info "New key generated"
echo ""
echo "New public key:"
cat "$data_path/id_ed25519.pub"
else
log_error "Failed to generate key"
return 1
fi
# Restart service
/etc/init.d/rustdesk start
}
cmd_status() {
defaults
echo "RustDesk Server Status"
echo "======================"
echo ""
echo "Configuration:"
echo " Enabled: $(uci_get enabled || echo '0')"
echo " ID Port: $id_port"
echo " Relay Port: $relay_port"
echo " Data Path: $data_path"
echo ""
# Check binaries
if [ -x "$data_path/hbbs" ]; then
echo "Binaries: Installed"
else
echo "Binaries: Not installed (run: rustdeskctl install)"
return 0
fi
# Check processes
echo ""
echo "Processes:"
if pgrep -f "hbbs.*-p.*$id_port" >/dev/null 2>&1; then
echo " hbbs (ID): RUNNING (port $id_port)"
else
echo " hbbs (ID): STOPPED"
fi
if pgrep -f "hbbr.*-p.*$relay_port" >/dev/null 2>&1; then
echo " hbbr (Relay): RUNNING (port $relay_port)"
else
echo " hbbr (Relay): STOPPED"
fi
# Show key
echo ""
if [ -f "$data_path/id_ed25519.pub" ]; then
echo "Public Key:"
echo " $(cat "$data_path/id_ed25519.pub")"
echo ""
echo "Client Configuration:"
echo " ID Server: $(uci -q get network.lan.ipaddr || echo '<router-ip>'):$id_port"
echo " Key: $(cat "$data_path/id_ed25519.pub")"
else
echo "Public Key: Not generated"
fi
}
cmd_logs() {
defaults
local follow=""
[ "$1" = "-f" ] && follow="-f"
if [ -f "$data_path/hbbs.log" ]; then
echo "=== hbbs log ==="
tail $follow -n 50 "$data_path/hbbs.log"
fi
if [ -f "$data_path/hbbr.log" ]; then
echo ""
echo "=== hbbr log ==="
tail $follow -n 50 "$data_path/hbbr.log"
fi
# Also check system log
if [ -z "$follow" ]; then
echo ""
echo "=== System log ==="
logread | grep -E "(hbbs|hbbr|rustdesk)" | tail -20
fi
}
cmd_configure_firewall() {
require_root || { log_error "Must run as root"; return 1; }
defaults
local changed=0
# Check if rules already exist
if ! uci show firewall 2>/dev/null | grep -q "RustDesk-ID"; then
log_info "Creating firewall rules..."
# ID server (TCP+UDP)
uci add firewall rule
uci set firewall.@rule[-1].name='RustDesk-ID-TCP'
uci set firewall.@rule[-1].src='wan'
uci set firewall.@rule[-1].dest_port="$id_port"
uci set firewall.@rule[-1].proto='tcp'
uci set firewall.@rule[-1].target='ACCEPT'
uci add firewall rule
uci set firewall.@rule[-1].name='RustDesk-ID-UDP'
uci set firewall.@rule[-1].src='wan'
uci set firewall.@rule[-1].dest_port="$id_port"
uci set firewall.@rule[-1].proto='udp'
uci set firewall.@rule[-1].target='ACCEPT'
# Relay server (TCP)
uci add firewall rule
uci set firewall.@rule[-1].name='RustDesk-Relay'
uci set firewall.@rule[-1].src='wan'
uci set firewall.@rule[-1].dest_port="$relay_port"
uci set firewall.@rule[-1].proto='tcp'
uci set firewall.@rule[-1].target='ACCEPT'
# NAT test (TCP)
uci add firewall rule
uci set firewall.@rule[-1].name='RustDesk-NAT'
uci set firewall.@rule[-1].src='wan'
uci set firewall.@rule[-1].dest_port='21115'
uci set firewall.@rule[-1].proto='tcp'
uci set firewall.@rule[-1].target='ACCEPT'
changed=1
fi
if [ "$changed" = "1" ]; then
uci commit firewall
/etc/init.d/firewall reload
log_info "Firewall rules created for ports 21115-21117"
else
log_info "Firewall rules already exist"
fi
uci_set firewall_wan '1' network
uci commit "$CONFIG"
}
cmd_mesh_register() {
defaults
if [ -x /usr/sbin/secubox-p2p ]; then
/usr/sbin/secubox-p2p register-service rustdesk "$id_port" 2>/dev/null
log_info "Registered RustDesk with mesh"
else
log_error "secubox-p2p not available"
return 1
fi
}
# ---------- service management ----------
cmd_service_run() {
require_root || exit 1
defaults
# Verify binaries
[ -x "$data_path/hbbs" ] || { log_error "hbbs not found"; exit 1; }
[ -x "$data_path/hbbr" ] || { log_error "hbbr not found"; exit 1; }
cd "$data_path" || exit 1
log_info "Starting RustDesk servers..."
# Start hbbs (ID server)
./hbbs -p "$id_port" -r "127.0.0.1:$relay_port" >> "$data_path/hbbs.log" 2>&1 &
HBBS_PID=$!
echo $HBBS_PID > "$data_path/hbbs.pid"
sleep 1
# Start hbbr (relay server)
./hbbr -p "$relay_port" >> "$data_path/hbbr.log" 2>&1 &
HBBR_PID=$!
echo $HBBR_PID > "$data_path/hbbr.pid"
log_info "hbbs started (PID: $HBBS_PID), hbbr started (PID: $HBBR_PID)"
# Wait for processes
trap 'cmd_service_stop; exit 0' TERM INT
wait
}
cmd_service_stop() {
defaults
log_info "Stopping RustDesk servers..."
# Kill by PID file
[ -f "$data_path/hbbs.pid" ] && kill $(cat "$data_path/hbbs.pid") 2>/dev/null
[ -f "$data_path/hbbr.pid" ] && kill $(cat "$data_path/hbbr.pid") 2>/dev/null
# Cleanup
rm -f "$data_path/hbbs.pid" "$data_path/hbbr.pid"
# Kill any remaining
pkill -f "hbbs.*-p.*$id_port" 2>/dev/null
pkill -f "hbbr.*-p.*$relay_port" 2>/dev/null
log_info "Servers stopped"
}
# ---------- main ----------
case "$1" in
install) cmd_install ;;
uninstall) cmd_uninstall ;;
status) cmd_status ;;
keygen) cmd_keygen ;;
logs) shift; cmd_logs "$@" ;;
configure-firewall) cmd_configure_firewall ;;
mesh-register) cmd_mesh_register ;;
service-run) cmd_service_run ;;
service-stop) cmd_service_stop ;;
*) usage; exit 1 ;;
esac