#!/bin/sh # RPCD handler for luci-app-rtty-remote # Provides RPC interface for RTTY Remote Control . /lib/functions.sh . /usr/share/libubox/jshn.sh # Load libraries [ -f /usr/lib/secubox/rtty-proxy.sh ] && . /usr/lib/secubox/rtty-proxy.sh [ -f /usr/lib/secubox/rtty-session.sh ] && . /usr/lib/secubox/rtty-session.sh [ -f /usr/lib/secubox/rtty-auth.sh ] && . /usr/lib/secubox/rtty-auth.sh RTTYCTL="/usr/sbin/rttyctl" #------------------------------------------------------------------------------ # Helper functions #------------------------------------------------------------------------------ get_config() { local section="$1" local option="$2" local default="$3" config_load rtty-remote config_get value "$section" "$option" "$default" echo "$value" } #------------------------------------------------------------------------------ # RPC Methods #------------------------------------------------------------------------------ # Get server status method_status() { json_init config_load rtty-remote local enabled config_get enabled main enabled '0' json_add_boolean "enabled" "$enabled" local port config_get port main server_port '7681' json_add_int "port" "$port" # Check if running if pgrep -f "rttyctl server-daemon" >/dev/null 2>&1; then json_add_boolean "running" 1 else json_add_boolean "running" 0 fi # Stats if [ -f /srv/rtty-remote/sessions.db ]; then local stats=$(session_stats 2>/dev/null) json_add_int "total_sessions" "$(echo "$stats" | jsonfilter -e '@.total_sessions' 2>/dev/null || echo 0)" json_add_int "active_sessions" "$(echo "$stats" | jsonfilter -e '@.active_sessions' 2>/dev/null || echo 0)" json_add_int "total_rpc_calls" "$(echo "$stats" | jsonfilter -e '@.total_rpc_calls' 2>/dev/null || echo 0)" json_add_int "unique_nodes" "$(echo "$stats" | jsonfilter -e '@.unique_nodes' 2>/dev/null || echo 0)" else json_add_int "total_sessions" 0 json_add_int "active_sessions" 0 json_add_int "total_rpc_calls" 0 json_add_int "unique_nodes" 0 fi json_dump } # Get mesh nodes method_get_nodes() { local nodes=$($RTTYCTL json-nodes 2>/dev/null) [ -z "$nodes" ] && nodes='{"nodes":[]}' echo "$nodes" } # Get single node details method_get_node() { local node_id read -r input json_load "$input" json_get_var node_id node_id [ -z "$node_id" ] && { echo '{"error":"Missing node_id"}' return } # Get node info from master-link or P2P json_init json_add_string "node_id" "$node_id" # Try to get address local addr=$($RTTYCTL node "$node_id" 2>&1 | grep "Address:" | awk '{print $2}') json_add_string "address" "$addr" # Check connectivity if [ -n "$addr" ] && ping -c 1 -W 2 "$addr" >/dev/null 2>&1; then json_add_string "status" "online" else json_add_string "status" "offline" fi json_dump } # Execute remote RPC call method_rpc_call() { local node_id object method params read -r input json_load "$input" json_get_var node_id node_id json_get_var object object json_get_var method method json_get_var params params [ -z "$node_id" ] || [ -z "$object" ] || [ -z "$method" ] && { echo '{"error":"Missing required parameters (node_id, object, method)"}' return } # Execute via rttyctl local result=$($RTTYCTL rpc "$node_id" "$object" "$method" "$params" 2>&1) local rc=$? json_init if [ $rc -eq 0 ]; then json_add_boolean "success" 1 # Try to parse result as JSON if echo "$result" | jsonfilter -e '@' >/dev/null 2>&1; then json_add_object "result" # Add result fields echo "$result" | jsonfilter -e '@' 2>/dev/null json_close_object else json_add_string "result" "$result" fi else json_add_boolean "success" 0 json_add_string "error" "$result" fi json_dump } # List remote RPCD objects method_rpc_list() { local node_id read -r input json_load "$input" json_get_var node_id node_id [ -z "$node_id" ] && { echo '{"error":"Missing node_id"}' return } local result=$($RTTYCTL rpc-list "$node_id" 2>&1) echo "$result" } # Get sessions method_get_sessions() { local node_id limit read -r input json_load "$input" json_get_var node_id node_id json_get_var limit limit [ -z "$limit" ] && limit=50 session_list "$node_id" "$limit" } # Start server method_server_start() { /etc/init.d/rtty-remote start 2>&1 json_init json_add_boolean "success" 1 json_dump } # Stop server method_server_stop() { /etc/init.d/rtty-remote stop 2>&1 json_init json_add_boolean "success" 1 json_dump } # Get settings method_get_settings() { json_init config_load rtty-remote json_add_object "main" local val config_get val main enabled '0' json_add_boolean "enabled" "$val" config_get val main server_port '7681' json_add_int "server_port" "$val" config_get val main auth_method 'master-link' json_add_string "auth_method" "$val" config_get val main session_ttl '3600' json_add_int "session_ttl" "$val" config_get val main max_sessions '10' json_add_int "max_sessions" "$val" json_close_object json_add_object "security" config_get val security require_wg '1' json_add_boolean "require_wg" "$val" config_get val security allowed_networks '' json_add_string "allowed_networks" "$val" json_close_object json_add_object "proxy" config_get val proxy rpc_timeout '30' json_add_int "rpc_timeout" "$val" config_get val proxy batch_limit '50' json_add_int "batch_limit" "$val" config_get val proxy cache_ttl '60' json_add_int "cache_ttl" "$val" json_close_object json_dump } # Set settings method_set_settings() { read -r input # Parse and apply settings local enabled=$(echo "$input" | jsonfilter -e '@.main.enabled' 2>/dev/null) [ -n "$enabled" ] && uci set rtty-remote.main.enabled="$enabled" local port=$(echo "$input" | jsonfilter -e '@.main.server_port' 2>/dev/null) [ -n "$port" ] && uci set rtty-remote.main.server_port="$port" local auth=$(echo "$input" | jsonfilter -e '@.main.auth_method' 2>/dev/null) [ -n "$auth" ] && uci set rtty-remote.main.auth_method="$auth" local ttl=$(echo "$input" | jsonfilter -e '@.main.session_ttl' 2>/dev/null) [ -n "$ttl" ] && uci set rtty-remote.main.session_ttl="$ttl" uci commit rtty-remote json_init json_add_boolean "success" 1 json_dump } # Replay session method_replay_session() { local session_id target_node read -r input json_load "$input" json_get_var session_id session_id json_get_var target_node target_node [ -z "$session_id" ] || [ -z "$target_node" ] && { echo '{"error":"Missing session_id or target_node"}' return } local result=$($RTTYCTL replay "$session_id" "$target_node" 2>&1) json_init json_add_boolean "success" 1 json_add_string "message" "$result" json_dump } # Connect to node (start terminal) method_connect() { local node_id read -r input json_load "$input" json_get_var node_id node_id [ -z "$node_id" ] && { echo '{"error":"Missing node_id"}' return } # Get node address local addr=$($RTTYCTL node "$node_id" 2>&1 | grep "Address:" | awk '{print $2}') json_init json_add_string "node_id" "$node_id" json_add_string "address" "$addr" json_add_string "terminal_url" "ws://localhost:7681/ws" json_add_string "ssh_command" "ssh root@$addr" json_dump } #------------------------------------------------------------------------------ # Main dispatcher #------------------------------------------------------------------------------ case "$1" in list) cat << 'EOF' { "status": {}, "get_nodes": {}, "get_node": {"node_id": "string"}, "rpc_call": {"node_id": "string", "object": "string", "method": "string", "params": "string"}, "rpc_list": {"node_id": "string"}, "get_sessions": {"node_id": "string", "limit": 50}, "server_start": {}, "server_stop": {}, "get_settings": {}, "set_settings": {"config": "object"}, "replay_session": {"session_id": "integer", "target_node": "string"}, "connect": {"node_id": "string"} } EOF ;; call) case "$2" in status) method_status ;; get_nodes) method_get_nodes ;; get_node) method_get_node ;; rpc_call) method_rpc_call ;; rpc_list) method_rpc_list ;; get_sessions) method_get_sessions ;; server_start) method_server_start ;; server_stop) method_server_stop ;; get_settings) method_get_settings ;; set_settings) method_set_settings ;; replay_session) method_replay_session ;; connect) method_connect ;; *) echo '{"error":"Unknown method"}' ;; esac ;; esac