# Proxy hotspot (integrado) **ADN DMR Peer Server** incluye un **proxy hotspot integrado**: un solo proceso (`adn-server.py`) acepta Homebrew (HBP) de muchos hotspots en un único puerto UDP e **inyecta** el tráfico en un **MASTER** configurado. **No** hace falta un proceso **`adn-proxy`** aparte cuando este modo está activo. La configuración está en **`adn-server.yaml`**, bloques **`PROXY`** y opcional **`SELF_SERVICE`** (misma tabla MySQL **`Clients`** que **adn-monitor**). --- ## Cuándo usarlo | Despliegue | Qué ejecutar | |------------|--------------| | **Stack ADN habitual** (monitor + panel + muchos hotspots Pi-Star) | **`adn-server.py`** con **`PROXY`** + **`SELF_SERVICE`**. | El proxy integrado usa **fan-in**: los hotspots solo necesitan **`PROXY.LISTEN_PORT`** (p. ej. **62031**). El **MASTER** destino es **solo inyección** — **no** abre su propio puerto UDP para ese system (sin rango de puertos por hotspot en el host del servidor). ```mermaid flowchart LR HS1[Hotspot A] -->|UDP HBP| LP[PROXY LISTEN_PORT] HS2[Hotspot B] -->|UDP HBP| LP LP -->|inyecta| MASTER[TARGET_SYSTEM MASTER] ``` --- ## Dependencia opcional (self-service) El self-service con MySQL requiere **`mysqlclient`**: ```bash pip install -e ".[selfservice]" ``` Si **`USE_SELFSERVICE: true`** pero falta **`mysqlclient`**, el arranque falla con un error claro. Pon **`USE_SELFSERVICE: false`** para usar el proxy sin BD (sin actualizaciones **RPTO** desde el panel). --- ## Claves `PROXY` | Clave | Rol | |-------|-----| | **LISTEN_PORT** | Puerto UDP al que se conectan los **hotspots** (el que configuran en el dispositivo). | | **LISTEN_IP** | Dirección de bind; vacío = todas las interfaces. | | **TARGET_SYSTEM** | Nombre del **MASTER** en **`SYSTEMS`** que recibe el HBP inyectado (debe existir y estar **ENABLED**). | | **TIMEOUT** | Timeout de sesión inactiva (segundos); las sesiones caducadas se eliminan en el MASTER. | | **DEBUG** | Log detallado de paquetes. | | **CLIENT_INFO** | Log de conexión/desconexión por ID de radio. | | **BLACK_LIST** | Bloquea IDs de radio listados. | | **IP_BLACK_LIST** | Bloquea IPs origen (con caducidad opcional). | En **`PROXY`** integrado **no** hay **`MASTER`**, **`PORT`** ni **`GENERATOR`** — eso corresponde al proxy independiente legado. El MASTER destino usa **`MAX_PEERS`** (no un rango UDP) para limitar hotspots simultáneos. Ejemplo (de `adn-server.example.yaml`): ```yaml PROXY: LISTEN_PORT: 62031 LISTEN_IP: "" TARGET_SYSTEM: SYSTEM TIMEOUT: 30 DEBUG: false CLIENT_INFO: true BLACK_LIST: [] IP_BLACK_LIST: {} ``` ### MASTER destino solo inyección Cuando **`PROXY.TARGET_SYSTEM`** apunta a un system (p. ej. **`SYSTEM`**), al arrancar se **eliminan** **`IP`** / **`PORT`** de ese bloque MASTER. Los hotspots nunca se conectan al puerto de conferencia; todo el HBP entra por **`LISTEN_PORT`**. Define **`MAX_PEERS`** en el MASTER destino como máximo de hotspots simultáneos (p. ej. **102**). Otros MASTER (**ECHO**, **D-APRS**, etc.) mantienen **`IP`** / **`PORT`** normales si no son el destino del proxy. --- ## Claves `SELF_SERVICE` Misma semántica que **`adn-monitor.yaml`** — tabla **`Clients`** compartida, flag **`modified`**, **RPTO** hacia el MASTER. | Clave | Rol | |-------|-----| | **USE_SELFSERVICE** | Activa sincronización de opciones con MySQL (`true` / `false`). | | **PBKDF2_SALT**, **PBKDF2_ITERATIONS** | Deben **coincidir** con **`adn-monitor.yaml`** para el hash de contraseñas. | La conexión MariaDB está en el bloque **`DATABASE`** (compartido con persistencia de TG dinámicos) — ver [Configuración](configuration.md#database-mariadb). Al arrancar el servidor registra **`(SELF_SERVICE) Database connection test: OK`** y **`(SELF_SERVICE) Enabled`** si el pool conecta. El self-service es **asíncrono**; el reenvío de voz no se bloquea por latencia de BD. Detalle del flujo en el panel: [Self-service](../../monitor/self-service.md). --- ## Comportamiento con varios hotspots - Cada hotspot autenticado es un **peer** en el MASTER de inyección con sus **OPTIONS** (TG estáticas). **Repeat** y el fan-out del monitor respetan **OPTIONS por peer** — el tráfico de un TG no se envía a peers que no lo tienen seleccionado. - Los talkgroups **eco 9990–9999** son **punto-a-punto**: omiten el filtro OPTIONS y vuelven **sólo** al peer exacto que originó la llamada (`RX_PEER` en el slot), nunca a otros hotspots del mismo usuario. Con un único peer conectado, se le entrega a ése (comportamiento legado). Ver [Echo — Comportamiento con varios hotspots](echo.md#comportamiento-con-varios-hotspots-proxy-inject-only) y [Números especiales](special-numbers.md). --- ## Comportamiento de la línea OPTIONS Tras el login (RPTL → RPTK → RPTC), el proxy arranca un **timer de 10 s** esperando el paquete **RPTO** del hotspot con su línea **OPTIONS**. Lo que el hotspot envíe (o no envíe) en ese RPTO determina **quién es la fuente de verdad** de los TG estáticos del peer: | El hotspot envía en el RPTO | Quién define los TG | Comportamiento | |---|---|---| | `OPTIONS=PASS=xxxxxx;` | **Auto-servicio** (panel web) | El proxy procesa el `PASS=`, verifica la contraseña individual (PBKDF2 contra `Clients.psswd`), marca al peer como autenticado, cancela el timer de 10 s y empuja los TG de la BD al master. El usuario **puede** hacer login por contraseña y auto-login por IP en el dashboard. | | `OPTIONS=` (vacío) | **Auto-servicio** (panel web) | El proxy lee los TG de la BD y los inyecta al master. El usuario **solo** puede usar auto-login por IP en el dashboard (sin contraseña). | | **No envía RPTO** (el timer de 10 s expira) | **Auto-servicio** (panel web) | El proxy asume que el hotspot no tiene OPTIONS propias y hace fallback a la BD. Mismo efecto que `OPTIONS=` vacío. | | `OPTIONS=TS2=730444;SINGLE=0;` (contenido sin `PASS=`) | **El propio hotspot** | El master toma los TG **directamente de la línea OPTIONS**. Se ignora la BD. El usuario **solo** puede usar auto-login por IP en el dashboard (sin contraseña). | **Regla clave:** el auto-servicio es la fuente de verdad **excepto** cuando el hotspot envía contenido explícito (TGs, SINGLE, TIMER, etc.) en su línea OPTIONS. En ese caso, lo que dice el hotspot **priman** y el auto-servicio se ignora. ### Contraseña individual y login por dashboard - Si el hotspot **nunca** envía `PASS=` en su RPTO, el usuario **no** podrá entrar al dashboard con contraseña. Solo podrá usar **auto-login por IP** (si su IP coincide con `Clients.host`). - Para habilitar el login por contraseña en el dashboard, el hotspot debe enviar `OPTIONS=PASS=tu_contraseña;` en su configuración (Pi-Star / WPSD / MMDVM `optsfile`). La contraseña debe coincidir con el hash PBKDF2 almacenado en `Clients.psswd`. - El flujo `PASS=` es lo que activa la sincronización bidireccional: el proxy almacena el hash, registra el flag `modified` y empuja los TG de la BD al master. --- ## Recarga en caliente (`SIGHUP`) **Se aplica sin reiniciar** (las sesiones activas del proxy se mantienen): - **`PROXY`:** **TIMEOUT**, **DEBUG**, **CLIENT_INFO**, **BLACK_LIST**, **IP_BLACK_LIST** - **`SELF_SERVICE`:** se fusiona en config (cambios de credenciales en nuevas operaciones BD; los bucles no se reinician en reload) **Requiere reinicio completo del proceso:** - **`PROXY.LISTEN_PORT`** / **`LISTEN_IP`** (el cambio de bind se registra y se ignora en reload) - **`PROXY.TARGET_SYSTEM`** - Activar o desactivar **`USE_SELFSERVICE`** tras el arranque Ver [Configuración — recarga en caliente](configuration.md#recarga-en-caliente-adn-serveryaml). --- ## Ver también - [Configuración](configuration.md) — referencia completa de **`adn-server.yaml`**. - [Monitorización e informes](monitoring.md) — informes TCP, panel, rotación de logs. - [Self-service](../../monitor/self-service.md) — **`Clients`**, temporización **RPTO**.