Browse Source

Add dual SSH tunnels: SSH + Dashboard access

Implemented two independent reverse SSH tunnels for remote device access:
- SSH Tunnel (ports 50000-59999): terminal access to device localhost:22
- Dashboard Tunnel (ports 60000-65535): web dashboard access to device localhost:80

Server Configuration:
- Fixed tunnel user shell from /usr/sbin/nologin to /bin/sh
- Added SSH daemon settings: AllowTcpForwarding, GatewayPorts, PermitTunnel
- Server-side port allocation and management
- Single ED25519 key for both tunnels

Device Implementation:
- Universal SSHTunnel manager supporting both tunnel types
- Fixed dashboard tunnel port from 8080 to 80
- Auto-reconnect on failure (5s delay)
- Server-controlled enable/disable via config

Documentation:
- Updated README.md with tunnel configuration and status
- Enhanced REVERSE_SHELL.md with dual tunnel architecture
- Added testing and usage examples
- Removed obsolete separate sshd configuration

Tested: Both tunnels working ✓

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
root 1 month ago
parent
commit
3eaa62469f
3 changed files with 208 additions and 118 deletions
  1. 25 5
      README.md
  2. 182 112
      REVERSE_SHELL.md
  3. 1 1
      cmd/beacon-daemon/main.go

+ 25 - 5
README.md

@@ -56,7 +56,8 @@ POE питание     → USB-A РАБОТАЕТ
   - Batching + gzip + HTTP POST на сервер
   - Batching + gzip + HTTP POST на сервер
   - Spooler (при отсутствии сети)
   - Spooler (при отсутствии сети)
   - HTTP API + WebSocket для dashboard (вкл/выкл с сервера)
   - HTTP API + WebSocket для dashboard (вкл/выкл с сервера)
-  - SSH туннель (reverse)
+  - SSH туннель (reverse, для терминала)
+  - Dashboard туннель (reverse, для веб-доступа)
   - Config polling (cloud mode)
   - Config polling (cloud mode)
 
 
 ## Device Modes
 ## Device Modes
@@ -155,7 +156,8 @@ AP Settings:
 │  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
 │  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
 │  │ Config      │  │ Registration│  │ SSH Tunnel          │  │
 │  │ Config      │  │ Registration│  │ SSH Tunnel          │  │
 │  │ Poller      │  │ Handler     │  │ Manager             │  │
 │  │ Poller      │  │ Handler     │  │ Manager             │  │
-│  │ (30s)       │  │             │  │ (reverse)           │  │
+│  │ (30s)       │  │             │  │ - SSH (22→50xxx)    │  │
+│  │             │  │             │  │ - Dashboard (80→60xxx)
 │  └─────────────┘  └─────────────┘  └─────────────────────┘  │
 │  └─────────────┘  └─────────────┘  └─────────────────────┘  │
 └─────────────────────────────────────────────────────────────┘
 └─────────────────────────────────────────────────────────────┘
         │                                    │
         │                                    │
@@ -362,8 +364,17 @@ make arm
     "server": "tunnel.example.com",
     "server": "tunnel.example.com",
     "port": 22,
     "port": 22,
     "user": "tunnel",
     "user": "tunnel",
-    "key_path": "/opt/mybeacon/etc/tunnel_key",
-    "remote_port": 12345,
+    "remote_port": 0,
+    "keepalive_interval": 30,
+    "reconnect_delay": 5
+  },
+
+  "dashboard_tunnel": {
+    "enabled": false,
+    "server": "tunnel.example.com",
+    "port": 22,
+    "user": "tunnel",
+    "remote_port": 0,
     "keepalive_interval": 30,
     "keepalive_interval": 30,
     "reconnect_delay": 5
     "reconnect_delay": 5
   }
   }
@@ -407,6 +418,14 @@ make arm
     "remote_port": 0,
     "remote_port": 0,
     "keepalive_interval": 30
     "keepalive_interval": 30
   },
   },
+  "dashboard_tunnel": {
+    "enabled": false,
+    "server": "tunnel.example.com",
+    "port": 22,
+    "user": "tunnel",
+    "remote_port": 0,
+    "keepalive_interval": 30
+  },
   "dashboard": {
   "dashboard": {
     "enabled": true
     "enabled": true
   },
   },
@@ -595,7 +614,8 @@ ssh root@<device-ip> '/etc/init.d/S98mybeacon restart'
 - [x] Dashboard remote control (enable/disable from server) - работает
 - [x] Dashboard remote control (enable/disable from server) - работает
 - [x] NTP management (auto-start on network up) - работает
 - [x] NTP management (auto-start on network up) - работает
 - [x] Spooler (offline queue) - работает
 - [x] Spooler (offline queue) - работает
-- [x] SSH Tunnel - реализовано (не тестировалось)
+- [x] SSH Tunnel (reverse, для терминала) - работает ✓
+- [x] Dashboard Tunnel (reverse, для веб-доступа) - работает ✓
 - [x] Logs optimization (tmpfs, rotation, spam reduction) - работает
 - [x] Logs optimization (tmpfs, rotation, spam reduction) - работает
 
 
 ## Known Issues
 ## Known Issues

+ 182 - 112
REVERSE_SHELL.md

@@ -1,4 +1,11 @@
-# Reverse SSH Tunnel для удалённого доступа
+# Reverse SSH Tunnels для удалённого доступа
+
+Система поддерживает **два независимых reverse туннеля** для доступа к устройствам за NAT:
+
+1. **SSH Tunnel (порты 50000-59999)** - доступ к терминалу устройства (localhost:22)
+2. **Dashboard Tunnel (порты 60000-65535)** - доступ к веб-дашборду (localhost:80)
+
+Оба туннеля управляются серверной конфигурацией и используют один ED25519 SSH ключ.
 
 
 ## Архитектура
 ## Архитектура
 
 
@@ -8,34 +15,32 @@
 │                                                                 │
 │                                                                 │
 │  sshd (port 22) ───────────> main SSH (admin access)           │
 │  sshd (port 22) ───────────> main SSH (admin access)           │
 │                                                                 │
 │                                                                 │
-│  sshd_tunnel (port 2222) ──> tunnel-only SSH                   │
-│      │                                                          │
-│      └──> /home/tunnel/.ssh/authorized_keys                    │
-│            (device pubkeys with restrictions)                  │
+│  Tunnel Access:                                                │
+│  ┌──────────────────────────────────────────────────────────┐  │
+│  │ SSH Tunnel Ports (50000-59999)                           │  │
+│  │   ssh -p {allocated_port} root@server                    │  │
+│  │   → устройство localhost:22 (терминал)                   │  │
+│  │                                                           │  │
+│  │ Dashboard Tunnel Ports (60000-65535)                     │  │
+│  │   http://server:{allocated_port}/                        │  │
+│  │   → устройство localhost:80 (веб-интерфейс)             │  │
+│  └──────────────────────────────────────────────────────────┘  │
 │                                                                 │
 │                                                                 │
-│  Admin Dashboard:                                              │
-│  ┌────────────────────────────────────┐                        │
-│  │ Device: 38:54:39:4b:1b:ac          │                        │
-│  │ [Open SSH] ──> Generate UUID       │                        │
-│  └────────────────────────────────────┘                        │
-│           │                                                     │
-│           └──> /admin/ssh/{uuid}                               │
-│                  │                                              │
-│                  └──> ttyd on localhost:random_port            │
-│                        ssh -p {allocated_port} root@localhost  │
+│  /home/tunnel/.ssh/authorized_keys                             │
+│    (device ED25519 pubkeys)                                    │
 │                                                                 │
 │                                                                 │
-│  Tunnel Status API:
+│  Port Allocation:                                              │
 │  ┌────────────────────────────────────┐                        │
 │  ┌────────────────────────────────────┐                        │
-│  │ POST /api/v1/tunnel-port           │                        │
-│  │ { device_id, port: 12345 }         │                        │
+│  │ Device: 38:54:39:4b:1b:ac          │                        │
+│  │ - SSH Tunnel Port: 50000           │                        │
+│  │ - Dashboard Tunnel Port: 60000     │                        │
+│  │ Status: Connected                  │                        │
 │  └────────────────────────────────────┘                        │
 │  └────────────────────────────────────┘                        │
 │                                                                 │
 │                                                                 │
-│  Audit Log:                                                    │
-│  - device_id                                                   │
-│  - admin_user                                                  │
-│  - session_uuid                                                │
-│  - timestamp                                                   │
-│  - commands (optional)                                         │
+│  SSH Config (/etc/ssh/sshd_config):                            │
+│  - AllowTcpForwarding yes                                      │
+│  - GatewayPorts yes                                            │
+│  - PermitTunnel yes                                            │
 └─────────────────────────────────────────────────────────────────┘
 └─────────────────────────────────────────────────────────────────┘
 
 
 ┌─────────────────────────────────────────────────────────────────┐
 ┌─────────────────────────────────────────────────────────────────┐
@@ -52,19 +57,31 @@
 │       (permissions: 0600, owner: root)                        │
 │       (permissions: 0600, owner: root)                        │
 │                                                                 │
 │                                                                 │
 │  SSH Tunnel (when enabled via server config):                 │
 │  SSH Tunnel (when enabled via server config):                 │
-│    ssh -N -R 0:localhost:22 \                                  │
-│        -p 2222 \                                               │
+│    # Туннель 1: SSH доступ (терминал)                         │
+│    ssh -N -R {ssh_remote_port}:localhost:22 \                 │
+│        -p 22 \                                                 │
 │        -o ServerAliveInterval=30 \                             │
 │        -o ServerAliveInterval=30 \                             │
 │        -o ServerAliveCountMax=3 \                              │
 │        -o ServerAliveCountMax=3 \                              │
 │        -o ExitOnForwardFailure=yes \                           │
 │        -o ExitOnForwardFailure=yes \                           │
-│        -i /opt/mybeacon/etc/tunnel_key \  
+│        -i /etc/beacon/ssh_tunnel_ed25519 \
 │        tunnel@server.com                                       │
 │        tunnel@server.com                                       │
 │                                                                 │
 │                                                                 │
-│    Parse allocated port from stderr →                         │
-│      POST /api/v1/tunnel-port                                 │
-│      { "device_id": "...", "port": 12345 }                    │
+│  Dashboard Tunnel (when enabled via server config):           │
+│    # Туннель 2: Dashboard доступ (веб-интерфейс)              │
+│    ssh -N -R {dashboard_remote_port}:localhost:80 \           │
+│        -p 22 \                                                 │
+│        -o ServerAliveInterval=30 \                             │
+│        -o ServerAliveCountMax=3 \                              │
+│        -o ExitOnForwardFailure=yes \                           │
+│        -i /etc/beacon/ssh_tunnel_ed25519 \                     │
+│        tunnel@server.com                                       │
+│                                                                 │
+│  Порты выделяются сервером (фиксированные):                   │
+│    - ssh_remote_port: 50000-59999                              │
+│    - dashboard_remote_port: 60000-65535                        │
 │                                                                 │
 │                                                                 │
 │  Auto-reconnect on disconnect (ReconnectDelay: 5s)            │
 │  Auto-reconnect on disconnect (ReconnectDelay: 5s)            │
+│  Max session lifetime: 24 hours                               │
 └─────────────────────────────────────────────────────────────────┘
 └─────────────────────────────────────────────────────────────────┘
 ```
 ```
 
 
@@ -483,7 +500,7 @@ if tunnelChanged {
 
 
 ```bash
 ```bash
 # На сервере
 # На сервере
-sudo useradd -m -d /home/tunnel -s /bin/false tunnel
+sudo useradd -m -d /home/tunnel -s /bin/sh tunnel
 sudo mkdir -p /home/tunnel/.ssh
 sudo mkdir -p /home/tunnel/.ssh
 sudo chmod 700 /home/tunnel/.ssh
 sudo chmod 700 /home/tunnel/.ssh
 sudo touch /home/tunnel/.ssh/authorized_keys
 sudo touch /home/tunnel/.ssh/authorized_keys
@@ -491,102 +508,46 @@ sudo chmod 600 /home/tunnel/.ssh/authorized_keys
 sudo chown -R tunnel:tunnel /home/tunnel/.ssh
 sudo chown -R tunnel:tunnel /home/tunnel/.ssh
 ```
 ```
 
 
-### 2. Конфиг отдельного sshd
-
-**Файл:** `/etc/ssh/sshd_tunnel_config`
-
-```sshd_config
-# Tunnel-only SSH daemon for MyBeacon devices
-Port 2222
-Protocol 2
-
-# Listening
-ListenAddress 0.0.0.0
-
-# Host keys (use existing)
-HostKey /etc/ssh/ssh_host_ed25519_key
-HostKey /etc/ssh/ssh_host_rsa_key
-
-# Logging
-SyslogFacility AUTH
-LogLevel INFO
-
-# Authentication
-PubkeyAuthentication yes
-AuthorizedKeysFile /home/tunnel/.ssh/authorized_keys
-PasswordAuthentication no
-ChallengeResponseAuthentication no
-KerberosAuthentication no
-GSSAPIAuthentication no
-PermitRootLogin no
-
-# Restrictions for tunnel user
-Match User tunnel
-    # ONLY port forwarding, nothing else
-    AllowTcpForwarding remote
-    GatewayPorts no
-    PermitOpen localhost:*
-
-    # Disable everything else
-    X11Forwarding no
-    AllowAgentForwarding no
-    PermitTTY no
-    PermitUserRC no
-
-    # Force command (ignored with -N, but extra safety)
-    ForceCommand /bin/echo "Port forwarding only"
-
-    # Limits
-    MaxSessions 10
-    ClientAliveInterval 30
-    ClientAliveCountMax 3
-
-    # Security
-    PermitEmptyPasswords no
-    MaxAuthTries 3
-```
+**ВАЖНО:** Используйте `/bin/sh` вместо `/bin/false` или `/usr/sbin/nologin` - иначе SSH сессия будет немедленно закрываться!
 
 
-### 3. Systemd unit для tunnel sshd
+### 2. Настройка SSH сервера
 
 
-**Файл:** `/etc/systemd/system/sshd-tunnel.service`
+Добавьте следующие настройки в `/etc/ssh/sshd_config`:
 
 
-```ini
-[Unit]
-Description=OpenSSH Tunnel Server for MyBeacon Devices
-After=network.target auditd.service
-ConditionPathExists=!/etc/ssh/sshd_tunnel_not_to_be_run
+```bash
+# Разрешить TCP forwarding для туннелей
+AllowTcpForwarding yes
 
 
-[Service]
-Type=notify
-EnvironmentFile=-/etc/default/ssh
-ExecStartPre=/usr/sbin/sshd -t -f /etc/ssh/sshd_tunnel_config
-ExecStart=/usr/sbin/sshd -D -f /etc/ssh/sshd_tunnel_config
-ExecReload=/bin/kill -HUP $MAINPID
-KillMode=process
-Restart=on-failure
-RestartSec=42s
+# Разрешить GatewayPorts для доступа извне (не только localhost)
+GatewayPorts yes
 
 
-[Install]
-WantedBy=multi-user.target
+# Разрешить туннели
+PermitTunnel yes
 ```
 ```
 
 
-Запуск:
+Перезапустите SSH сервер:
 
 
 ```bash
 ```bash
-sudo systemctl daemon-reload
-sudo systemctl enable sshd-tunnel
-sudo systemctl start sshd-tunnel
-sudo systemctl status sshd-tunnel
+sudo systemctl restart sshd
 ```
 ```
 
 
-### 4. Firewall правила
+**Объяснение:**
+- `AllowTcpForwarding yes` - разрешает reverse SSH tunnels
+- `GatewayPorts yes` - разрешает bind на 0.0.0.0 (доступ извне), а не только на 127.0.0.1
+- `PermitTunnel yes` - разрешает туннелирование
+
+### 3. Firewall правила
 
 
 ```bash
 ```bash
-# Разрешить порт 2222 для tunnel SSH
-sudo ufw allow 2222/tcp comment "MyBeacon SSH Tunnel"
+# Разрешить порты 50000-59999 для SSH Tunnel
+sudo ufw allow 50000:59999/tcp comment "MyBeacon SSH Tunnel"
+
+# Разрешить порты 60000-65535 для Dashboard Tunnel
+sudo ufw allow 60000:65535/tcp comment "MyBeacon Dashboard Tunnel"
 
 
 # Или для iptables
 # Или для iptables
-sudo iptables -A INPUT -p tcp --dport 2222 -j ACCEPT
+sudo iptables -A INPUT -p tcp --dport 50000:59999 -j ACCEPT
+sudo iptables -A INPUT -p tcp --dport 60000:65535 -j ACCEPT
 ```
 ```
 
 
 ## Серверное API
 ## Серверное API
@@ -935,6 +896,115 @@ async def ssh_session_stats():
 - [ ] Audit log записи
 - [ ] Audit log записи
 - [ ] Переподключение туннеля при обрыве
 - [ ] Переподключение туннеля при обрыве
 
 
+## Тестирование и использование
+
+### Проверка статуса туннелей на сервере
+
+```bash
+# Проверить что порты слушают
+ss -tlnp | grep -E ':(50000|60000)'
+
+# Пример вывода:
+# LISTEN 0      128        0.0.0.0:50000      0.0.0.0:*
+# LISTEN 0      128        0.0.0.0:60000      0.0.0.0:*
+```
+
+### SSH Tunnel - доступ к терминалу
+
+```bash
+# Подключение к устройству через SSH tunnel
+ssh -p 50000 root@server-ip
+
+# Или через ProxyJump (если доступ через промежуточный сервер)
+ssh -J user@server -p 50000 root@localhost
+```
+
+### Dashboard Tunnel - доступ к веб-интерфейсу
+
+```bash
+# Через браузер
+http://server-ip:60000/
+
+# Или через curl
+curl http://server-ip:60000/api/status
+```
+
+**Пример ответа:**
+```json
+{
+  "device_id": "38:54:39:4b:1b:ac",
+  "registered": true,
+  "mode": "cloud",
+  "uptime_sec": 400,
+  "network": {
+    "eth0_ip": "192.168.5.244/24",
+    "gateway": "192.168.5.1"
+  },
+  "scanners": {
+    "ble_running": true,
+    "wifi_running": true
+  }
+}
+```
+
+### Логи туннелей на устройстве
+
+```bash
+# На устройстве просмотреть логи
+ssh root@device-ip "tail -f /var/log/mybeacon.log | grep tunnel"
+
+# Пример вывода:
+# [ssh-tunnel] Started: 192.168.5.2:22 -> localhost:22 (remote_port=50000)
+# [dashboard-tunnel] Started: 192.168.5.2:22 -> localhost:80 (remote_port=60000)
+```
+
+### Управление туннелями через server API
+
+```python
+# Включить SSH туннель
+POST /api/v1/admin/update_device
+{
+  "device_id": "38:54:39:4b:1b:ac",
+  "password": "12345678",
+  "patch": {
+    "ssh_tunnel.enabled": true
+  }
+}
+
+# Включить Dashboard туннель
+POST /api/v1/admin/update_device
+{
+  "device_id": "38:54:39:4b:1b:ac",
+  "password": "12345678",
+  "patch": {
+    "dashboard_tunnel.enabled": true
+  }
+}
+```
+
+После получения новой конфигурации (≤30 секунд) устройство:
+1. Запустит соответствующий туннель
+2. Подключится к серверу
+3. Сервер выделит фиксированный порт из диапазона
+4. Туннель будет доступен по этому порту
+
+### Отладка проблем
+
+```bash
+# На сервере: проверить активные SSH сессии от tunnel user
+sudo ps aux | grep 'sshd.*tunnel'
+
+# На сервере: логи SSH
+sudo journalctl -u sshd -f | grep tunnel
+
+# На устройстве: проверить процессы туннелей
+ps aux | grep 'ssh.*192.168'
+
+# На устройстве: убить зависший туннель
+killall ssh
+# Демон автоматически перезапустит туннели через 5 секунд
+```
+
 ## Ссылки
 ## Ссылки
 
 
 - **ttyd**: https://github.com/tsl0922/ttyd
 - **ttyd**: https://github.com/tsl0922/ttyd

+ 1 - 1
cmd/beacon-daemon/main.go

@@ -130,7 +130,7 @@ func main() {
 		KeepaliveInterval: cfg.DashboardTunnel.KeepaliveInterval,
 		KeepaliveInterval: cfg.DashboardTunnel.KeepaliveInterval,
 		ReconnectDelay:    cfg.DashboardTunnel.ReconnectDelay,
 		ReconnectDelay:    cfg.DashboardTunnel.ReconnectDelay,
 	}
 	}
-	dashboardTunnel := NewSSHTunnel("dashboard", 8080, dashboardTunnelCfg)
+	dashboardTunnel := NewSSHTunnel("dashboard", 80, dashboardTunnelCfg)
 
 
 	// Create scanner manager
 	// Create scanner manager
 	scanners := NewScannerManager(*binDir, cfg.Debug)
 	scanners := NewScannerManager(*binDir, cfg.Debug)