From b198bb754a3389485eca858ebe1efee33f1250ed Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Sun, 25 Jan 2026 15:44:43 +0100 Subject: [PATCH] feat(exposure): Add SecuBox Service Exposure Manager New unified tool for service exposure management: - Port conflict detection and resolution (scan, conflicts, fix-port) - Dynamic Tor hidden service management (tor add/list/remove) - HAProxy SSL reverse proxy configuration (ssl add/list/remove) Commands: secubox-exposure scan # List listening services secubox-exposure conflicts # Detect port collisions secubox-exposure tor add gitea # Create .onion for service secubox-exposure ssl add svc domain # Add HAProxy SSL backend Co-Authored-By: Claude Opus 4.5 --- package/secubox/secubox-app-exposure/Makefile | 42 ++ .../files/etc/config/secubox-exposure | 63 ++ .../files/usr/sbin/secubox-exposure | 657 ++++++++++++++++++ 3 files changed, 762 insertions(+) create mode 100644 package/secubox/secubox-app-exposure/Makefile create mode 100644 package/secubox/secubox-app-exposure/files/etc/config/secubox-exposure create mode 100755 package/secubox/secubox-app-exposure/files/usr/sbin/secubox-exposure diff --git a/package/secubox/secubox-app-exposure/Makefile b/package/secubox/secubox-app-exposure/Makefile new file mode 100644 index 0000000..5afba63 --- /dev/null +++ b/package/secubox/secubox-app-exposure/Makefile @@ -0,0 +1,42 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=secubox-app-exposure +PKG_VERSION:=1.0.0 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=SecuBox Team +PKG_LICENSE:=MIT + +include $(INCLUDE_DIR)/package.mk + +define Package/secubox-app-exposure + SECTION:=secubox + CATEGORY:=SecuBox + TITLE:=SecuBox Service Exposure Manager + DEPENDS:=+secubox-core +tor +haproxy + PKGARCH:=all +endef + +define Package/secubox-app-exposure/description + Unified service exposure manager for SecuBox. + - Port conflict detection and resolution + - Dynamic Tor hidden service management + - HAProxy SSL reverse proxy configuration +endef + +define Package/secubox-app-exposure/conffiles +/etc/config/secubox-exposure +endef + +define Build/Compile +endef + +define Package/secubox-app-exposure/install + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) ./files/etc/config/secubox-exposure $(1)/etc/config/ + + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) ./files/usr/sbin/secubox-exposure $(1)/usr/sbin/ +endef + +$(eval $(call BuildPackage,secubox-app-exposure)) diff --git a/package/secubox/secubox-app-exposure/files/etc/config/secubox-exposure b/package/secubox/secubox-app-exposure/files/etc/config/secubox-exposure new file mode 100644 index 0000000..7912ceb --- /dev/null +++ b/package/secubox/secubox-app-exposure/files/etc/config/secubox-exposure @@ -0,0 +1,63 @@ +# SecuBox Service Exposure Manager Configuration + +config settings 'main' + option enabled '1' + option tor_enabled '1' + option ssl_enabled '1' + option haproxy_config '/srv/lxc/haproxy/rootfs/etc/haproxy/haproxy.cfg' + option haproxy_certs '/srv/lxc/haproxy/rootfs/etc/haproxy/certs' + option tor_hidden_dir '/var/lib/tor/hidden_services' + option tor_config '/etc/tor/torrc' + +# Port ranges for auto-assignment +config ports 'ranges' + option app_start '8100' + option app_end '8199' + option monitoring_start '8200' + option monitoring_end '8299' + +# Known service definitions with default ports +config known 'gitea' + option default_port '3000' + option config_path 'gitea.main.http_port' + option category 'app' + +config known 'streamlit' + option default_port '8501' + option config_path 'streamlit.main.port' + option category 'app' + +config known 'hexojs' + option default_port '4000' + option config_path 'hexojs.main.port' + option category 'app' + +config known 'cyberfeed' + option default_port '8082' + option config_path 'cyberfeed.main.port' + option category 'app' + +config known 'crowdsec' + option default_port '6060' + option config_file '/etc/crowdsec/config.yaml' + option category 'security' + +config known 'netifyd' + option default_port '8086' + option config_path 'netifyd.main.port' + option category 'monitoring' + +config known 'domoticz' + option default_port '8080' + option config_type 'docker' + option category 'app' + +# Service exposure entries (dynamically managed) +# Example: +# config service 'gitea' +# option port '3000' +# option local '1' +# option tor '1' +# option tor_onion 'abc123xyz.onion' +# option ssl '1' +# option ssl_domain 'git.example.com' diff --git a/package/secubox/secubox-app-exposure/files/usr/sbin/secubox-exposure b/package/secubox/secubox-app-exposure/files/usr/sbin/secubox-exposure new file mode 100755 index 0000000..3fcc3d7 --- /dev/null +++ b/package/secubox/secubox-app-exposure/files/usr/sbin/secubox-exposure @@ -0,0 +1,657 @@ +#!/bin/sh +# +# SecuBox Service Exposure Manager +# Unified tool for port management, Tor hidden services, and HAProxy SSL +# + +. /lib/functions.sh +. /usr/share/libubox/jshn.sh + +CONFIG_NAME="secubox-exposure" +HAPROXY_CONFIG="" +HAPROXY_CERTS="" +TOR_HIDDEN_DIR="" +TOR_CONFIG="" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +NC='\033[0m' + +log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } +log_ok() { echo -e "${GREEN}[OK]${NC} $1"; } +log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } +log_err() { echo -e "${RED}[ERROR]${NC} $1"; } + +load_config() { + config_load "$CONFIG_NAME" + config_get HAPROXY_CONFIG main haproxy_config "/srv/lxc/haproxy/rootfs/etc/haproxy/haproxy.cfg" + config_get HAPROXY_CERTS main haproxy_certs "/srv/lxc/haproxy/rootfs/etc/haproxy/certs" + config_get TOR_HIDDEN_DIR main tor_hidden_dir "/var/lib/tor/hidden_services" + config_get TOR_CONFIG main tor_config "/etc/tor/torrc" + config_get APP_PORT_START ranges app_start "8100" + config_get APP_PORT_END ranges app_end "8199" +} + +# ============================================================================ +# PORT SCANNING & CONFLICT DETECTION +# ============================================================================ + +get_listening_ports() { + # Returns: port address process + netstat -tlnp 2>/dev/null | grep LISTEN | awk '{ + split($4, a, ":") + port = a[length(a)] + if (!seen[port]++) { + split($7, p, "/") + proc = p[2] + if (proc == "") proc = "unknown" + print port, $4, proc + } + }' | sort -n +} + +cmd_scan() { + log_info "Scanning listening services..." + echo "" + printf "%-6s %-20s %-15s %-10s\n" "PORT" "ADDRESS" "PROCESS" "STATUS" + printf "%-6s %-20s %-15s %-10s\n" "------" "--------------------" "---------------" "----------" + + get_listening_ports | while read port addr proc; do + # Determine if external + case "$addr" in + *0.0.0.0*|*::*) status="${GREEN}external${NC}" ;; + *127.0.0.1*|*::1*) status="${YELLOW}local${NC}" ;; + *) status="${CYAN}bound${NC}" ;; + esac + printf "%-6s %-20s %-15s " "$port" "$addr" "$proc" + echo -e "$status" + done + echo "" +} + +cmd_conflicts() { + log_info "Checking for port conflicts..." + echo "" + + local conflicts=0 + local TMP_PORTS="/tmp/ports_$$" + + # Get all configured ports from UCI + > "$TMP_PORTS" + + # Check known services + check_known_service() { + local section="$1" + local default_port config_path + config_get default_port "$section" default_port + config_get config_path "$section" config_path + + if [ -n "$config_path" ]; then + # Extract UCI config and option + local uci_config=$(echo "$config_path" | cut -d'.' -f1) + local uci_option=$(echo "$config_path" | cut -d'.' -f2-) + local actual_port=$(uci -q get "$config_path" 2>/dev/null) + [ -z "$actual_port" ] && actual_port="$default_port" + echo "$actual_port $section" >> "$TMP_PORTS" + fi + } + config_foreach check_known_service known + + # Find duplicates + sort "$TMP_PORTS" | uniq -d -w5 | while read port svc; do + log_warn "Port $port is configured for multiple services!" + grep "^$port " "$TMP_PORTS" | while read p s; do + echo " - $s" + done + conflicts=$((conflicts + 1)) + done + + # Check against actually listening ports + get_listening_ports | while read port addr proc; do + if grep -q "^$port " "$TMP_PORTS"; then + local configured_svc=$(grep "^$port " "$TMP_PORTS" | head -1 | cut -d' ' -f2) + # Check if process matches expected + case "$configured_svc" in + gitea) [ "$proc" != "gitea" ] && log_warn "Port $port: expected gitea, found $proc" ;; + streamlit) echo "$proc" | grep -qv "python\|streamlit" && log_warn "Port $port: expected streamlit, found $proc" ;; + esac + fi + done + + rm -f "$TMP_PORTS" + + if [ "$conflicts" -eq 0 ]; then + log_ok "No port conflicts detected" + fi +} + +find_free_port() { + local start="$1" + local end="$2" + local port="$start" + + while [ "$port" -le "$end" ]; do + if ! netstat -tlnp 2>/dev/null | grep -q ":$port "; then + echo "$port" + return 0 + fi + port=$((port + 1)) + done + return 1 +} + +cmd_fix_port() { + local service="$1" + local new_port="$2" + + if [ -z "$service" ]; then + log_err "Usage: secubox-exposure fix-port [new_port]" + return 1 + fi + + load_config + + # Get service config + local config_path default_port + config_get config_path "$service" config_path + config_get default_port "$service" default_port + + if [ -z "$config_path" ]; then + log_err "Unknown service: $service" + return 1 + fi + + # Find free port if not specified + if [ -z "$new_port" ]; then + new_port=$(find_free_port "$APP_PORT_START" "$APP_PORT_END") + if [ -z "$new_port" ]; then + log_err "No free ports available in range $APP_PORT_START-$APP_PORT_END" + return 1 + fi + fi + + # Check if new port is free + if netstat -tlnp 2>/dev/null | grep -q ":$new_port "; then + log_err "Port $new_port is already in use" + return 1 + fi + + log_info "Changing $service port to $new_port" + + # Update UCI + if uci set "$config_path=$new_port" && uci commit; then + log_ok "UCI config updated" + + # Restart service if it has an init script + if [ -x "/etc/init.d/$service" ]; then + log_info "Restarting $service..." + /etc/init.d/"$service" restart + fi + + log_ok "$service now listening on port $new_port" + else + log_err "Failed to update UCI config" + return 1 + fi +} + +# ============================================================================ +# TOR HIDDEN SERVICES +# ============================================================================ + +cmd_tor_add() { + local service="$1" + local local_port="$2" + local onion_port="${3:-80}" + + if [ -z "$service" ]; then + log_err "Usage: secubox-exposure tor add [local_port] [onion_port]" + return 1 + fi + + load_config + + # Get local port from config if not specified + if [ -z "$local_port" ]; then + config_get local_port "$service" default_port + if [ -z "$local_port" ]; then + log_err "Cannot determine local port for $service" + return 1 + fi + fi + + local hidden_dir="$TOR_HIDDEN_DIR/$service" + + # Create hidden service directory + mkdir -p "$hidden_dir" + chmod 700 "$hidden_dir" + chown tor:tor "$hidden_dir" 2>/dev/null || chown debian-tor:debian-tor "$hidden_dir" 2>/dev/null + + # Check if already configured in torrc + if grep -q "HiddenServiceDir $hidden_dir" "$TOR_CONFIG" 2>/dev/null; then + log_warn "Hidden service for $service already exists" + local onion=$(cat "$hidden_dir/hostname" 2>/dev/null) + [ -n "$onion" ] && log_info "Onion address: $onion" + return 0 + fi + + # Add to torrc + log_info "Adding hidden service for $service (127.0.0.1:$local_port -> :$onion_port)" + + cat >> "$TOR_CONFIG" << EOF + +# Hidden service for $service (added by secubox-exposure) +HiddenServiceDir $hidden_dir +HiddenServicePort $onion_port 127.0.0.1:$local_port +EOF + + # Restart Tor + log_info "Restarting Tor..." + /etc/init.d/tor restart 2>/dev/null || systemctl restart tor 2>/dev/null + + # Wait for onion address + log_info "Waiting for onion address generation..." + local tries=0 + while [ ! -f "$hidden_dir/hostname" ] && [ "$tries" -lt 30 ]; do + sleep 1 + tries=$((tries + 1)) + done + + if [ -f "$hidden_dir/hostname" ]; then + local onion=$(cat "$hidden_dir/hostname") + log_ok "Hidden service created!" + echo "" + echo -e " ${CYAN}Service:${NC} $service" + echo -e " ${CYAN}Onion:${NC} $onion" + echo -e " ${CYAN}Port:${NC} $onion_port -> 127.0.0.1:$local_port" + echo "" + + # Save to UCI + uci set "${CONFIG_NAME}.${service}=service" + uci set "${CONFIG_NAME}.${service}.port=$local_port" + uci set "${CONFIG_NAME}.${service}.tor=1" + uci set "${CONFIG_NAME}.${service}.tor_onion=$onion" + uci set "${CONFIG_NAME}.${service}.tor_port=$onion_port" + uci commit "$CONFIG_NAME" + else + log_err "Failed to generate onion address" + return 1 + fi +} + +cmd_tor_list() { + load_config + + log_info "Tor Hidden Services:" + echo "" + printf "%-15s %-62s %-10s\n" "SERVICE" "ONION ADDRESS" "PORT" + printf "%-15s %-62s %-10s\n" "---------------" "--------------------------------------------------------------" "----------" + + # List from filesystem + if [ -d "$TOR_HIDDEN_DIR" ]; then + for dir in "$TOR_HIDDEN_DIR"/*/; do + [ -d "$dir" ] || continue + local svc=$(basename "$dir") + local onion="" + [ -f "$dir/hostname" ] && onion=$(cat "$dir/hostname") + + # Get port from torrc + local port=$(grep -A1 "HiddenServiceDir $dir" "$TOR_CONFIG" 2>/dev/null | grep HiddenServicePort | awk '{print $2}') + + if [ -n "$onion" ]; then + printf "%-15s %-62s %-10s\n" "$svc" "$onion" "${port:-80}" + fi + done + fi + echo "" +} + +cmd_tor_remove() { + local service="$1" + + if [ -z "$service" ]; then + log_err "Usage: secubox-exposure tor remove " + return 1 + fi + + load_config + + local hidden_dir="$TOR_HIDDEN_DIR/$service" + + if [ ! -d "$hidden_dir" ]; then + log_err "No hidden service found for $service" + return 1 + fi + + log_info "Removing hidden service for $service" + + # Remove from torrc (remove the block) + sed -i "/# Hidden service for $service/,/HiddenServicePort/d" "$TOR_CONFIG" + + # Remove directory + rm -rf "$hidden_dir" + + # Update UCI + uci delete "${CONFIG_NAME}.${service}.tor" 2>/dev/null + uci delete "${CONFIG_NAME}.${service}.tor_onion" 2>/dev/null + uci delete "${CONFIG_NAME}.${service}.tor_port" 2>/dev/null + uci commit "$CONFIG_NAME" + + # Restart Tor + /etc/init.d/tor restart 2>/dev/null || systemctl restart tor 2>/dev/null + + log_ok "Hidden service removed" +} + +# ============================================================================ +# HAPROXY SSL BACKENDS +# ============================================================================ + +cmd_ssl_add() { + local service="$1" + local domain="$2" + local local_port="$3" + + if [ -z "$service" ] || [ -z "$domain" ]; then + log_err "Usage: secubox-exposure ssl add [local_port]" + return 1 + fi + + load_config + + # Get local port from config if not specified + if [ -z "$local_port" ]; then + config_get local_port "$service" default_port + # Try to get from service UCI + local config_path + config_get config_path "$service" config_path + if [ -n "$config_path" ]; then + local configured_port=$(uci -q get "$config_path") + [ -n "$configured_port" ] && local_port="$configured_port" + fi + if [ -z "$local_port" ]; then + log_err "Cannot determine local port for $service. Specify it manually." + return 1 + fi + fi + + # Check if HAProxy config exists + if [ ! -f "$HAPROXY_CONFIG" ]; then + log_err "HAProxy config not found: $HAPROXY_CONFIG" + return 1 + fi + + # Check if already configured + if grep -q "backend ${service}_backend" "$HAPROXY_CONFIG"; then + log_warn "Backend for $service already exists in HAProxy config" + return 0 + fi + + log_info "Adding SSL backend for $service ($domain -> 127.0.0.1:$local_port)" + + # Create backend config + local backend_config=" +# Backend for $service (added by secubox-exposure) +backend ${service}_backend + mode http + option httpchk GET / + http-request set-header X-Forwarded-Proto https + server ${service} 127.0.0.1:$local_port check +" + + # Add ACL to https frontend + local acl_line=" acl host_${service} hdr(host) -i $domain" + local use_line=" use_backend ${service}_backend if host_${service}" + + # Check if https-in frontend exists + if grep -q "frontend https-in" "$HAPROXY_CONFIG"; then + # Add ACL and use_backend before the default_backend line + sed -i "/frontend https-in/,/default_backend/ { + /default_backend/ i\\ +$acl_line\\ +$use_line + }" "$HAPROXY_CONFIG" + else + log_warn "No https-in frontend found. Adding basic HTTPS frontend." + cat >> "$HAPROXY_CONFIG" << EOF + +frontend https-in + bind *:443 ssl crt $HAPROXY_CERTS/ + mode http + option httplog +$acl_line +$use_line + default_backend default_backend +EOF + fi + + # Add backend at end of file + echo "$backend_config" >> "$HAPROXY_CONFIG" + + # Save to UCI + uci set "${CONFIG_NAME}.${service}=service" + uci set "${CONFIG_NAME}.${service}.port=$local_port" + uci set "${CONFIG_NAME}.${service}.ssl=1" + uci set "${CONFIG_NAME}.${service}.ssl_domain=$domain" + uci commit "$CONFIG_NAME" + + log_ok "HAProxy backend added for $service" + log_info "Domain: $domain -> 127.0.0.1:$local_port" + log_warn "Note: You need to add SSL certificate for $domain to $HAPROXY_CERTS/" + log_info "Reloading HAProxy..." + + # Reload HAProxy (in LXC container) + if [ -x "/usr/sbin/haproxyctl" ]; then + /usr/sbin/haproxyctl reload + else + lxc-attach -n haproxy -- /etc/init.d/haproxy reload 2>/dev/null || \ + /etc/init.d/haproxy reload 2>/dev/null + fi + + log_ok "SSL backend configured" +} + +cmd_ssl_list() { + load_config + + log_info "HAProxy SSL Backends:" + echo "" + printf "%-15s %-30s %-20s\n" "SERVICE" "DOMAIN" "BACKEND" + printf "%-15s %-30s %-20s\n" "---------------" "------------------------------" "--------------------" + + # Parse from HAProxy config + if [ -f "$HAPROXY_CONFIG" ]; then + grep -E "^backend .+_backend$" "$HAPROXY_CONFIG" | while read line; do + local backend=$(echo "$line" | awk '{print $2}') + local service=$(echo "$backend" | sed 's/_backend$//') + + # Get domain from ACL + local domain=$(grep "acl host_${service} " "$HAPROXY_CONFIG" | awk '{print $NF}') + + # Get server line + local server=$(grep -A5 "backend $backend" "$HAPROXY_CONFIG" | grep "server " | awk '{print $3}') + + printf "%-15s %-30s %-20s\n" "$service" "${domain:-N/A}" "${server:-N/A}" + done + fi + echo "" +} + +cmd_ssl_remove() { + local service="$1" + + if [ -z "$service" ]; then + log_err "Usage: secubox-exposure ssl remove " + return 1 + fi + + load_config + + if [ ! -f "$HAPROXY_CONFIG" ]; then + log_err "HAProxy config not found" + return 1 + fi + + if ! grep -q "backend ${service}_backend" "$HAPROXY_CONFIG"; then + log_err "No backend found for $service" + return 1 + fi + + log_info "Removing SSL backend for $service" + + # Remove ACL and use_backend lines + sed -i "/acl host_${service} /d" "$HAPROXY_CONFIG" + sed -i "/use_backend ${service}_backend/d" "$HAPROXY_CONFIG" + + # Remove backend block + sed -i "/# Backend for $service/,/^$/d" "$HAPROXY_CONFIG" + sed -i "/^backend ${service}_backend$/,/^$/d" "$HAPROXY_CONFIG" + + # Update UCI + uci delete "${CONFIG_NAME}.${service}.ssl" 2>/dev/null + uci delete "${CONFIG_NAME}.${service}.ssl_domain" 2>/dev/null + uci commit "$CONFIG_NAME" + + # Reload HAProxy + if [ -x "/usr/sbin/haproxyctl" ]; then + /usr/sbin/haproxyctl reload + else + lxc-attach -n haproxy -- /etc/init.d/haproxy reload 2>/dev/null || \ + /etc/init.d/haproxy reload 2>/dev/null + fi + + log_ok "SSL backend removed" +} + +# ============================================================================ +# STATUS & HELP +# ============================================================================ + +cmd_status() { + load_config + + echo "" + echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}" + echo -e "${CYAN} SecuBox Service Exposure Status${NC}" + echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}" + echo "" + + # Count services + local total_services=$(get_listening_ports | wc -l) + local external_services=$(get_listening_ports | grep -E "0\.0\.0\.0|::" | wc -l) + + echo -e "${BLUE}Services:${NC}" + echo " Total listening: $total_services" + echo " External (0.0.0.0): $external_services" + echo "" + + # Tor status + local tor_services=0 + [ -d "$TOR_HIDDEN_DIR" ] && tor_services=$(ls -1 "$TOR_HIDDEN_DIR" 2>/dev/null | wc -l) + echo -e "${BLUE}Tor Hidden Services:${NC} $tor_services" + if [ "$tor_services" -gt 0 ]; then + for dir in "$TOR_HIDDEN_DIR"/*/; do + [ -d "$dir" ] || continue + local svc=$(basename "$dir") + local onion=$(cat "$dir/hostname" 2>/dev/null) + [ -n "$onion" ] && echo " - $svc: ${onion:0:16}..." + done + fi + echo "" + + # HAProxy backends + local ssl_backends=0 + [ -f "$HAPROXY_CONFIG" ] && ssl_backends=$(grep -c "^backend.*_backend$" "$HAPROXY_CONFIG" 2>/dev/null || echo 0) + echo -e "${BLUE}HAProxy SSL Backends:${NC} $ssl_backends" + if [ "$ssl_backends" -gt 0 ] && [ -f "$HAPROXY_CONFIG" ]; then + grep -E "^backend .+_backend$" "$HAPROXY_CONFIG" | while read line; do + local backend=$(echo "$line" | awk '{print $2}' | sed 's/_backend$//') + echo " - $backend" + done + fi + echo "" + echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}" +} + +cmd_help() { + cat << EOF +SecuBox Service Exposure Manager + +Usage: secubox-exposure [options] + +COMMANDS: + scan Scan all listening services + conflicts Detect port conflicts + fix-port [port] Change service port (auto-assigns if no port given) + status Show exposure status summary + + tor add [port] Create Tor hidden service + tor list List hidden services + tor remove Remove hidden service + + ssl add Add HAProxy SSL backend + ssl list List SSL backends + ssl remove Remove SSL backend + +EXAMPLES: + secubox-exposure scan + secubox-exposure conflicts + secubox-exposure fix-port domoticz 8180 + + secubox-exposure tor add gitea + secubox-exposure tor add streamlit 8501 80 + secubox-exposure tor list + + secubox-exposure ssl add gitea git.example.com + secubox-exposure ssl add streamlit app.example.com 8501 + secubox-exposure ssl list + +EOF +} + +# ============================================================================ +# MAIN +# ============================================================================ + +case "$1" in + scan) + cmd_scan + ;; + conflicts) + load_config + cmd_conflicts + ;; + fix-port) + cmd_fix_port "$2" "$3" + ;; + status) + cmd_status + ;; + tor) + case "$2" in + add) cmd_tor_add "$3" "$4" "$5" ;; + list) cmd_tor_list ;; + remove) cmd_tor_remove "$3" ;; + *) log_err "Usage: secubox-exposure tor {add|list|remove}"; exit 1 ;; + esac + ;; + ssl) + case "$2" in + add) cmd_ssl_add "$3" "$4" "$5" ;; + list) cmd_ssl_list ;; + remove) cmd_ssl_remove "$3" ;; + *) log_err "Usage: secubox-exposure ssl {add|list|remove}"; exit 1 ;; + esac + ;; + help|--help|-h) + cmd_help + ;; + *) + cmd_help + exit 1 + ;; +esac