🕯 Candela Softcam
Candela es un servidor softcam P2P de código cerrado desarrollado por Javier Sayago (Javilonas). Gestiona el descifrado de canales de televisión de pago mediante tarjetas físicas y emulación por software, con un protocolo P2P propietario cifrado, WebIf completo y compatibilidad DVBAPI para receptores Enigma2, VDR y Tvheadend.
Características principales
| Módulo | Descripción | Estado |
|---|---|---|
| Protocolo P2P | Protocolo Candela cifrado ChaCha20-Poly1305 + LZ4. Handshake ECDH efímero. | Activo |
| SoftCam Emulator | Descifrado por software usando SoftCam.Key. Soporta Nagra, NDS, Viaccess, SECA, Irdeto, BISS, Conax, Cryptoworks, Betacrypt. | Activo |
| DVBAPI | Interfaz para receptores DVB (Enigma2, VDR, Tvheadend). TCP en Windows, TCP/Unix socket en Linux. | Activo |
| StreamRelay (iDVB) | Motor CSA SIMD nativo para descifrado de streams TS en tiempo real. | Activo |
| Lectores de tarjeta | Lectores PC/SC, Phoenix, Dragon y hardware interno (decos Enigma2). | Activo |
| WebIf | Interfaz web Vue 3, CSS autónomo, assets embebidos en el binario. HTTP o HTTPS. | Activo |
| FakeCW Detection | 3 capas: blacklist estática, heurística estructural (patrónes ACS), dinámica (hop+latencia+ciclo SM). | Activo |
| DoubleCheck CW | Requiere confirmación de 2 peers antes de aceptar una CW. Mayoría de 3 como desempate. | Opt-in |
| Forense ACF | Arsenal de herramientas de diagnóstico: EMM Vault, APDU Fuzzer, CW Inspector, Nagra Calc, ECM Simulator/Fuzzer, CW Brute-Force, Timeline Forense ECM, Inspector Payload ECM. | Activo |
| PFS / ECDH X25519 | Perfect Forward Secrecy con intercambio de clave efímero X25519 por sesión. Cada sesión tiene clave única - comprometer una no afecta a las demás. | Activo R30 |
| Mensajería P2P | Canal de mensajes cifrado entre peers autenticados. Los mensajes viajan cifrados con la clave de sesión ChaCha20-Poly1305. | Activo R31 |
| Red P2P - Identidad y Acceso | Puerto P2P, NodeID, nombre de operador (gossip), Ghost UA anti-fingerprint, filtro de IPs, límite de conexiónes por IP. Failban automático con alertas por umbral, audit log y config log. | Activo R32+ |
| ETO - ECM Timing Oracle | Perfilado estadístico de latencia ECM por peer y CAID. Detecta tarjetas degradadas, emuladores y cambios de clave por firma temporal. Histograma 16 cubos + anomalías 3σ. | Activo R33 |
| CWS - Consensus Shield | Extensión del DoubleCheck con votación N-peer. Neutraliza CWs envenenadas de operadoras: la CW ganada por quórum se entrega, el peer que divergió se penaliza. | Activo R33 |
| ERD - ECM Replay Detector | Retardo sintético adaptativo en cache hits para imitar el timing real de la tarjeta (~300ms). Evita que operadoras detecten el softcam por respuestas <5ms. No bloqueante. | Activo R33 |
| CFI - CAS Fingerprint Inversion | Evolución de ERD: aplica solo el retardo mínimo histórico por CAID (ETO floor) en lugar de la media. Más rápido para el usuario, igualmente opaco para el operador. Compensación de tiempo transcurrido: si la ECM ya tardó más que el floor, no se añade retardo adicional. | Activo R36 |
| EFG - ECM Flow Guard | Anti-cascade: ring buffer lock-free por peer que detecta resharing por diversidad de SIDs. Strict Cache Mode dinámico con auto-recovery. Ignora zapping legítimo. | Activo R33 |
| CWRID - CW Replay Detector | Ventana deslizante de hashes de CW. Detecta reutilización de CW entre ECMs distintas (replay) y entrega de la misma CW a múltiples canales (lateral sharing). | Activo R33 |
| EEA - ECM Entropy Analyzer | Calcula la entropía Shannon de cada CW por CAID. Alerta si H < 7.0 bits/byte: CW constante, nula o patrón fijo indica fake CW o fallo CAS. | Activo R33 |
| ECLD - Latency Decomposer | Registra timestamps T0–T4 (recibida, cache, upstream, respuesta, entregada). Ring buffer de cadenas completas con desglose: lookup, RTT upstream, entrega. | Activo R33 |
| OLG - ECM Overlap Guard | En cache miss, entrega inmediatamente la última CW válida del canal al demux como "puente". Evita pantalla negra mientras el upstream resuelve la ECM nueva. | Activo R33 |
| Adaptive ECM Timeout | Timeout de ECM adaptativo por CAID usando la media ETO×3. Canales rápidos no esperan el timeout global completo; canales lentos no se cortan prematuramente. | Activo R33 |
| CTC - Transport Camouflage | Framing Fake TLS 1.3 Record Layer (5 bytes/paquete). Supera bloqueos ISP por "lista blanca" en eventos. Opt-in, retrocompatible. SNI sintético o personalizado. I/O via writev (cero copia). | Activo R34 |
| CPM - Adaptive Pulse Masking | Inyecta CMD_PADDING de 200-1400 bytes cada 2-3.5s por peer. Rompe la firma temporal del criptoperíodo DVB (latido de 10s). PRNG xorshift32 sin syscalls. ~5-10 kbps/peer. Sin hilos adicionales. | Activo R35 |
| PIR - Peer Intelligence Ring | Inteligencia colectiva distribuida: cuando un nodo detecta un scanner o ataque, comparte el evento con todos sus peers autenticados vía CMD_REP_SHARE. Watchlist local con TTL configurable. | Activo R36 |
| NETMAP - Network Topology Map | Descubrimiento de topología completa de la red mediante gossip P2P puro (CMD_NET_MAP). Un nodo con un solo peer aprende la existencia de todos los nodos. Cero credenciales viajan nunca - solo metadatos públicos (nombre, país, versión de protocolo, flags), cifrados con ECDH. El reenvío gossip solo ocurre cuando al menos una entrada es genuinamente nueva o ha cambiado, evitando bucles de retransmisión entre peers (corregido R39). | Activo R37 |
| NSS - Node Status Signal | El nodo anuncia su apagado a todos sus peers (CMD_GOING_DOWN). Los receptores reconectan inmediatamente sin esperar el timeout - sin pantalla negra en apagados planificados. | Activo R37 |
| NRS - Node Reputation Score | Puntuación 0–100 por servidor upstream (latencia 50% + estabilidad 30% + ECMs 20%). El watchdog ordena los servidores por score - el mejor se intenta primero. | Activo R37 |
| Anti-Eclipse | Límite de peers activos por bloque /24 (max_peers_per_subnet, default 2). Previene ataques de aislamiento de red. | Activo R37 |
| Anti-Scanner - Honeypot + CAID Probe | CAIDs trampa configurables (honeypot_caids): cualquier peer que los solicite es baneado al instante. Ventana deslizante de CAIDs únicos por peer: si supera el umbral configurable en la ventana temporal, se detecta como scanner/bot y es expulsado. | Activo R35+ |
| ECDH-first Handshake (Protocolo v2) | Las credenciales (usuario+contraseña) viajan siempre bajo clave ECDH efímera X25519 - nunca con la clave bootstrap estática conocida. El servidor rechaza cualquier CMD_HELLO sin ECDH previo activo. | Activo R35+ |
| SCC - Simultaneous Channel Cap | Limita el número de SRVIDs activos simultáneamente en el lector local (scc_max_channels). Un SRVID expira si no llegan ECMs en scc_window_s segundos (default 30). Evita que el sistema CA de la operadora detecte acceso a un número anómalo de canales en paralelo. | Activo R38 |
| ETS - ECM Temporal Spreading | Cuando llegan ECMs de múltiples canales nuevos en ráfaga (zapping rápido o inicio), las distribuye en el tiempo dentro de una ventana configurable (ets_max_spread_ms, default 2000ms). Evita el pico de ECMs simultáneas que delataría el softcam ante el sistema CA. | Activo R38 |
| Proxy Universal | Enrutamiento del tráfico P2P a través de proxy SOCKS4/SOCKS5/HTTP CONNECT/Tor/I2P (proxy_type, proxy_host). Útil para nodos detrás de CGNAT o para anonimizar el origen de las conexiónes P2P. | Activo R39 |
| GSP - Gossip Shuffle Privacy | Aplica Fisher-Yates parcial al orden de propagación del gossip (netmap_gossip_max). Rompe el patrón determinista de reenvío de CMD_NET_MAP que un observador externo podría usar para inferir la topología de la red. | Activo R39 |
| ECM Relay | Oculta qué nodo sirve físicamente a qué cliente: las ECMs se reenvían a través del nodo intermediario usando CMD_ECM_RELAY (0x17) / CMD_ECM_RELAY_RESP (0x18). Un observador externo solo ve comunicación entre los nodos adyacentes, no el origen real. | Activo R39 |
| MCRR - Multi-Card Round-Robin | Cuando hay varios lectores de tarjeta físicos, distribuye las ECMs por SRVID entre ellos (enable_mcrr). Reduce la carga por lector y mejora la capacidad total de resolución de ECMs simultáneas. | Activo R39 |
| NewCamd / MGcamd - Servidor y Cliente | Candela puede actuar como servidor NewCamd/MGcamd (acepta conexiónes de NCam, OSCam, receptores compatibles) y como cliente (conecta a servidores NewCamd/MGcamd de terceros para obtener CWs). Filtrado IP por servidor (allowed), límite de clientes (max_clients), keepalive configurable y Modo Candela. | Activo R40 |
| Modo Candela - Capa ChaCha20 anti-DPI | Capa de cifrado adicional ChaCha20 sobre el tráfico NewCamd/MGcamd entre nodos Candela. Se negocia automáticamente via magic bytes CNDL en el payload de login. Si el cliente no soporta Modo Candela, cae en modo legado sin interrumpir la conexión. Clave derivada con SHA-256(session_key14 || "CANDELA_LAYER_V1"). | Activo R40 |
Compatibilidad de plataformas
| SO / Dispositivo | Compilación | Notas |
|---|---|---|
| Windows x64 | MinGW-w64 GCC 15.2.0 (MSYS2) | Binario estático, sin dependencias extra. |
| Linux x64 | GCC 3.12+ | Incluye soporte epoll nativo. |
| Linux ARM/MIPS | GCC cross-compile | Enigma2 (Dreambox, Vu+, Octagon, etc.). |
| Android | NDK | Via Termux o como servicio. Sin WebIf en pantalla pequeña. |
🔒 Seguridad y privacidad
Protocolo P2P - qué se transmite y qué no
| Dato | ¿Sale por red? | Explicación |
|---|---|---|
| CAID:PROVID de la tarjeta | Solo capacidades | Solo se anuncian via CMD_CARD_MAP. Son datos públicos visibles en cualquier flujo DVB en abierto. No identifican la tarjeta individual. |
| UA (Unique Address / número de serie tarjeta) | NUNCA | La interfaz Message Passing filtra la UA antes de pasarla al protocolo. Solo la ve el sistema de lectura local. |
| ATR de la tarjeta | NUNCA | El ATR identifica el chip. Nunca sale del sistema de lectura. |
| Tiers / Entitlements | NUNCA | Los paquetes contratados de la tarjeta no se transmiten por red. |
| RSA Key / BoxKey / CWEKey | NUNCA | Las claves de la tarjeta solo viven en memoria del proceso local. No se serializan ni envían por red. |
| ECM (datos) | Cifrado P2P | Las ECMs se transmiten cifradas con ChaCha20-Poly1305 + LZ4. Sin clave de sesión no son legibles. |
| CW (Control Word) | Cifrado P2P | Ídem. La CW en tránsito está cifrada. En reposo en caché RAM, nunca en disco sin cifrar. |
| IP de peers | Solo conectados | Las IPs de peers solo se muestran en el WebIf local. No se anuncian a terceros. |
| NodeID | Anonimizado | El NodeID es un hash aleatorio generado al arrancar. No contiene info del hardware ni del usuario. |
| Ghost UA | Configurable | Bytes hex opcionales que simulan ser otro softcam para confundir sistemas DPI de operadoras. |
CacheEX y seguridad
CacheEX permite que peers intercambien entradas de caché CW proactivamente. Dentro de una red de peers de confianza (misma persona u organización), esto es seguro porque todos los paquetes están cifrados con la clave de sesión ChaCha20-Poly1305.
Anti-fingerprinting y Anti-DPI
- Jitter estocástico: los paquetes CMD_CARD_MAP se retrasan 50–300ms aleatorios para romper correlación temporal DPI.
- Padding aleatorio: proto_send_packet añade bytes de padding para que todos los paquetes tengan tamaño variable, imposibilitando identificar el tipo por longitud.
- Ghost UA: bytes hex configurables que imitan el patrón de otro softcam conocido.
- Silent Mode: cuando activo, no se escribe nada en consola. Los logs van solo a fichero.
- NodeID: hash de 64 bits aleatorio, regenerable desde WebIf.
- CTC (Candela Transport Camouflage): framing TLS 1.3 Application Data - para el ISP es tráfico HTTPS estándar. Implementado en R34.
- CPM (Adaptive Pulse Masking): chaff cifrado continuo cada 2–3.5s - entierra el patrón silencio/ráfaga del criptoperíodo DVB. Implementado en R35.
- TAR - Anti-DPI Suite (R37): PSN (normalización de tamaño a buckets fijos), ETJ (jitter temporal en ECMs), CTF (tráfico de fondo constante), TCR (rotación de sesión TCP). Cobertura: 100% ante DPI en tiempo real, análisis estadístico, autocorrelación temporal y metadatos de duración de sesión.
¿Puede la operadora detectar el uso de Candela?
Hay que distinguir dos capas de amenaza con vectores y soluciones completamente distintos:
Capa 1 - ISP / red: el ISP ve paquetes cifrados circulando entre nodos. Hasta R36, un DPI avanzado podía identificar cardsharing por el perfil de tráfico (tamaño de paquetes, patrón temporal, silencios, duración de sesión). Con CTC + CPM + TAR (PSN+ETJ+CTF+TCR) activos, el tráfico es indistinguible de HTTPS estándar ante DPI en tiempo real, análisis estadístico, autocorrelación temporal y metadatos de sesión. Cobertura en esta capa: 100%. El ISP no puede detectar ni bloquear selectivamente el tráfico P2P de Candela.
Capa 2 - Sistema CA de la operadora: si hay tarjeta física local, la operadora procesa internamente cada ECM que llega a esa tarjeta en su propio backend de acceso condicional. Este canal es independiente de la red y no está expuesto al ISP - no hay ningún paquete que camuflar porque la operadora es el destino legítimo. Si una tarjeta sirve muchos canales simultáneos, el volumen de ECMs en el sistema CA de la operadora es mayor que el de un suscriptor normal. Candela implementa ECM ratelimit y caché CW para mantener la tasa dentro de rangos plausibles. En modo puro P2P sin tarjeta local, esta capa no aplica - la operadora no tiene visibilidad directa.
🏗 Arquitectura interna
Flujo de una ECM de extremo a extremo
Receptor DVB (Enigma2/VDR) → DVBAPI [Puerto 9000]
↓ ECM raw (CAID:SRVID:datos)
ECM Handler - válidación + deduplicación + hash MD5
↓
Caché CW - ¿ya resuelta? → CW inmediata al receptor
↓ si no está en caché
Motor HLS - priorización de peers (Hop 0 > Hop 1 > Hop N)
↓
Protocolo P2P Candela - CMD_ECM_REQ → peers upstream [ChaCha20-Poly1305+LZ4]
↓ respuesta CMD_CW_RESP
FakeCW Detection - 3 capas + DoubleCheck opcional
↓ CW válida
Caché CW - guardar para futuras peticiónes
↓
DVBAPI → Receptor DVB - canal descifrado ✓
📊 Pestaña Panel (Dashboard)
Vista general del estado del sistema en tiempo real. Se actualiza cada 2 segundos mediante polling diferencial - solo actualiza la sección visible.
Barra de métricas
Barra compacta flex-wrap con widgets de estado:
| Widget | Descripción | Implementación |
|---|---|---|
| Uptime | Tiempo en ejecución sin reiniciar. | Calculado desde arranque del proceso. |
| RAM (privada) | Memoria privada del proceso - igual que el Administrador de Tareas. | Windows: PrivateUsage · Linux: VmRSS-RssFile-RssShmem |
| CPU (proceso) | % de CPU consumido por el proceso Candela. | Delta GetProcessTimes//proc/self/stat entre llamadas. Primera muestra = 0% (sin delta previo). |
| Peers | Número de peers P2P activos (clientes + upstream). | Contador en tiempo real. |
| Nodos Red | Nodos Candela vistos en la red vía Node Gossip. Clicable: abre el panel lateral en la pestaña Nodos. | Polling cada 30s vía /api/nodes. Disponible desde el arranque, sin necesidad de abrir el panel de seguridad. |
| Protocolo | Versión del protocolo en uso. | Dinámico desde API (/api/stats → campo proto_version). Se actualiza automáticamente con la versión del servidor. |
Módulos (pills)
Indicadores verdes/rojos del estado de cada módulo: DVBAPI, SoftCam, StreamRelay, ACF. Verde = activo y funciónando.
Panel lateral de seguridad (campana 🔔)
El icono de campana en la barra de navegación abre un panel lateral deslizante con cuatro pestañas independientes, cada una con su propio scroll:
| Pestaña | Contenido | Polling |
|---|---|---|
| 🔔 Alertas | Gráfica de intentos de acceso fallidos (60 min), lista de eventos de seguridad, IPs bloqueadas, whitelist activa. Incluye acciones rápidas: bloquear/desbloquear IP, añadir a whitelist, marcar evento como leído, y botón Desbloquear todas para liberar todas las IPs bloqueadas de una sola acción. Los eventos de seguridad muestran descripciones legibles en español (Bloqueo manual, Scanner P2P detectado, Honeypot activado, etc.) en lugar de identificadores internos del protocolo. El botón de pestaña muestra un badge rojo con eventos de seguridad no leídos y un badge naranja 🚫 N con el número de IPs bloqueadas actualmente. | Cada 10s vía /api/security/events. |
| ⚖️ Cárcel | Peers P2P penalizados temporalmente por envío de CWs falsas (Anti-Fake HLS). Muestra IP, usuario, tiempo restante de penalización y contador de fakes. Botón "Perdonar" para liberar antes de tiempo. | Cada 10s vía /api/security/jail. |
| 🌐 Nodos | Mapa de nodos Candela en la red vía NETMAP gossip: NodeID, nombre de operador, país, versión de protocolo, hops, NRS score. Cada nodo enlaza a su página dedicada candela_netmap.html#nodeID. Accesible también desde el widget "Nodos Red" del dashboard. | Cada 30s vía /api/peers/netmap. Cargado al arrancar. |
| 🚫 BorraOff | Peers penalizados por caídas prolongadas (sistema BorraOff). Muestra usuario, nivel de penalización (AVISO/PENALIZADO/BLOQUEADO), fecha de desconexión y si tiene notificación pendiente. Botón "Resetear" para limpiar penalización. | Al abrir el panel vía /api/borraoff. |
| 🌐 Nodos (NETMAP) | Mapa de nodos Candela en la red via gossip. Debajo, si hay peers descubiertos en la red local vía LAN Discovery, aparece la sección Detectados en la LAN con IP:puerto y NodeID de cada instancia encontrada. Estos peers no están conectados - hay que añadirlos manualmente en Config > Servidores. | /api/peers/netmap + /api/peers/lan |
Clientes Conectados
Lista de peers que se han conectado a este Candela como clientes (consumen CWs). Por cada cliente se muestra: IP/usuario, tarjetas anunciadas, canal visionando, ECMs envíadas, latencia y flags activos.
| Flag | Significado |
|---|---|
| CW-Push | Este cliente recibe CWs proactivamente sin pedir ECMs. |
| NoCache | Este cliente no usa la caché - siempre resuelve en vivo. |
| CacheOnly | Este cliente solo puede usar caché, no genera ECMs al upstream. |
Servidores Upstream
Peers a los que este Candela se conecta como cliente para pedir CWs. Muestra tarjetas anunciadas, CWs resueltas OK y latencia HLS media.
📡 Pestaña Monitor
Diagnóstico operativo en tiempo real. Muestra lo que está pasando ahora mismo en el sistema - a diferencia de Forense ACF que es para análisis histórico o dirigido.
Latencia ECM en tiempo real
Gráfico Chart.js actualizado cada 2 segundos con la latencia media de las últimas ECMs resueltas. Permite detectar degradación de rendimiento de peers upstream o saturación de la red.
Demuxes DVBAPI activos
Tabla de los demuxes que el receptor DVB tiene abiertos en este momento. Por cada demux:
| Campo | Descripción |
|---|---|
| Demux | Índice del demux del receptor (0=primera sintonía, 1=segunda, etc.). |
| SRVID | Service ID del canal que se está descifrando. |
| CAID | Sistema de acceso condicional del canal. |
| ProvID | Provider ID del operador. |
| Canal | Nombre del canal si está en candela.srvid. |
| Latencia | Tiempo desde la petición ECM hasta recibir la CW. <300ms=verde, <600ms=amarillo, >=rojo. |
| Hop | Número de saltos hasta la tarjeta que resuelve. 0=local, 1=peer directo, N=cascada. |
Live CW Inspector
Visor en tiempo real de las CWs activas entregadas a cada demux. Muestra canal, CAID:SRVID, CW even/odd en hex, peer de origen, latencia y hop. Útil para verificar que las CWs llegan correctamente antes de que el receptor las aplique.
Actividad Interna (canales FTA)
Demuxes cuya PMT no contiene descriptores CA (sin acceso condicional). Candela los registra con CAID 0xFFFE y los muestra en la tabla igual que el resto, pero sin latencia ECM ni peer asignado. Su entrada persiste 300 segundos sin actividad (frente a 60s para canales cifrados) porque los FTA no generan ECMs periodicas.
Rastro de Origen (caché)
Para cada CW entregada, muestra su origen: caché RAM, ECM DB en disco, peer upstream, lector local (Hop 0) o SoftCam emulador. Permite identificar qué fuente está resolviendo cada canal en tiempo real.
Duración de sesión y clientes históricos
Tabla de clientes P2P conectados con tiempo de sesión activo y estadísticas acumuladas desde el arranque: ECMs servidas, CWs entregadas, FakeCWs rechazadas. Los clientes históricos (ya desconectados) se conservan en memoria hasta reiniciar.
Árbol de Saltos por Canal
Visualización del grafo de peers para cada CAID:SRVID: qué peer resuelve qué canal, en cuántos saltos, con qué latencia media. Permite identificar cuellos de botella en la topología P2P y optimizar la distribución de peers.
ECM Inspector
¿Por qué está en Monitor y no en Forense?
El ECM Inspector loguea automáticamente cada ECM: su hash, CAID:SRVID, el peer que la resolvió, la latencia y si la CW resultante fue aceptada, rechazada por FakeCW, pendiente de DoubleCheck o resuelta desde caché. Implementado con tommy_hashlin O(1) desde R32 - sin impacto de rendimiento aunque haya 1024 ECMs pendientes.
🔍 Pestaña Diagnóstico ECM
Vista centralizada del estado de descifrado canal por canal. Responde a la pregunta "¿por qué este canal no abre?" sin necesidad de revisar logs ni ficheros de configuración. A diferencia del Monitor (que muestra el flujo operativo en tiempo real), Diagnóstico ECM acumula histórico y expone la causa raíz automáticamente por cada canal.
Vista unificada de canales activos
Tabla con todos los canales que el receptor DVB ha envíado al daemon, independientemente de si están cifrados o no. Cruza los datos del DVBAPI (demux activo) con el histórico de peticiónes ECM para ofrecer una visión completa:
| Campo | Descripción |
|---|---|
| Canal / SRVID | Nombre del servicio si está en candela.srvid, junto al Service ID en hex. |
| CAID : ProvID | Sistema de acceso condicional y proveedor. Los canales FTA, TDT, IPTV y unicast sin CA aparecen marcados como fta. |
| Estado | Último resultado de la petición ECM: ok_cache, ok_local, reader_ocupado, denegado, pendiente_red. |
| Fuente | Origen que resolvió la CW: cache, local, newcamd, mgcamd, red (peer P2P). |
| Causa | Diagnóstico automático: lector al límite de paralelo, ECM filtrada por candela.prio, sin lector compatible, encolado en red, etc. |
| Éxitos / Busy / Denegados | Contadores acumulados desde el arranque del daemon para ese SRVID. |
API: GET /api/diag/channels. Los canales FTA persisten en la tabla el mismo tiempo que los cifrados; ambos se limpian si el demux cierra.
Carga de lectores locales
Panel que muestra, para cada lector de tarjeta físico o emulador configurado, cuántos SRVIDs (canales) tiene activos en este momento y el porcentaje de uso respecto al límite max_parallel configurado. La barra de uso se pone en rojo al superar el 80%.
Si MCRR está activo, el desglose muestra qué canal está asignado a cada reader. Si un reader está al 100% de uso y hay ECMs en estado reader_ocupado, esta vista identifica el cuello de botella de forma inmediata.
API: GET /api/diag/readers.
Modo preview y sugerencias de reglas
Cuando el modo preview está activo (diag_preview_mode=1), el daemon acumula resultados por CAID:PROVID:SRVID y clasifica automáticamente cada canal:
- P: CAID:PROVID SRVID — canal que siempre resuelve en local o en caché. Candidato a regla ALLOW en candela.prio para asegurarse de que siempre se prioriza localmente.
- I: CAID:PROVID SRVID — canal sistemáticamente denegado o sin lector. Candidato a regla SKIP para descartarlo y no malgastar peticiónes ECM.
- revisar — canal inestable con resultados mixtos. Requiere revisión manual antes de crear una regla.
Las sugerencias se muestran en una tabla con botónes ALLOW y SKIP por fila. Al pulsar cualquiera de ellos la regla se añade directamente a candela.prio y entra en vigor sin reiniciar. El modo preview no modifica ningúna regla por sí solo: todo es opt-in.
APIs: GET /api/diag/suggestions para obtener la lista, POST /api/diag/suggestions/reset para limpiar el histórico acumulado.
Panel de reglas candela.prio
Vista y gestión directa del fichero candela.prio sin salir de la pestaña Diagnóstico:
- Tabla de reglas activas: tipo (ALLOW en verde, SKIP en rojo), CAID, PROVID, SRVID y comentario. Botón de eliminación por fila con efecto inmediato en memoria y en disco.
- Formulario de alta: tipo, CAID (hex), PROVID (hex), SRVID opcional y comentario libre. Al guardar la regla entra en vigor al instante.
- Aplicar sugerencias: los botónes ALLOW/SKIP de la tabla de sugerencias crean la regla correspondiente con un solo clic, sin copiar valores manualmente.
El fichero también puede editarse como texto plano desde la pestaña Editor, donde está disponible el editor de candela.prio junto al resto de ficheros de configuración.
APIs: GET /api/diag/prio (lista JSON de reglas), POST /api/diag/prio/add, POST /api/diag/prio/remove, GET /api/diag/prio/raw, POST /api/diag/prio/raw.
Estado CW y ECM PID por canal
Card que muestra, para cada canal cifrado activo, los siguientes datos en tiempo real:
| Campo | Descripción |
|---|---|
| ECM PID | PID del flujo ECM extraído de la PMT DVB. Identifica qué sistema CA está activo para el canal. Si aparece 0000 el receptor no ha enviado la PMT aún o el canal es FTA. |
| CW even (key 00) | Control Word par activa en hex (8 bytes). Es la clave que el STB usa para descifrar los paquetes con scrambling_control=10. |
| CW odd (key 01) | Control Word impar activa en hex (8 bytes). Usada con scrambling_control=11. Las dos rotan de forma alternada cada criptoperíodo. |
| Edad CW | Segundos transcurridos desde que se entregó la última CW. En verde (<8s), naranja (8-12s) y rojo (>12s). Una edad alta indica que el siguiente descifrado llegará tarde y el canal puede cortarse. |
API: GET /api/diag/cw_state. Los datos se obtienen cruzando el contexto de demux activo (ecm_pid) con el historial de CW del ciclo de verificación.
Actividad EMM por CAID
Las EMMs (Entitlement Management Messages) son los mensajes que el canal emite para gestionar suscripciones y renovar derechos en las tarjetas. Esta card muestra, agrupado por CAID:
| Campo | Descripción |
|---|---|
| Total | Número total de EMMs recibidas para ese CAID desde el arranque del daemon. |
| Tasa | EMMs por minuto estimadas en el último intervalo de 60 segundos. En verde (<3/min), naranja (3-10/min) y rojo (>10/min). Una tasa muy alta puede indicar renovación forzada o actividad anómala del sistema CA. |
| Última | Tiempo transcurrido desde la última EMM recibida. Si lleva varios minutos sin EMMs y el canal empieza a fallar, la tarjeta puede estar perdiendo derechos. |
API: GET /api/diag/emm_stats.
Sparklines de latencia por reader
Cada lector (NewCamd cliente, MGcamd cliente y hardware físico) almacena un ring buffer de las últimas 20 latencias medidas en cada ECM resuelta con éxito. La pestaña Diagnóstico muestra una mini-gráfica SVG por reader donde:
- El eje Y representa la latencia en ms (escala automática al rango de valores del reader).
- El color de la línea es verde (<200ms), naranja (200-500ms) o rojo (>500ms) según la media EMA actual.
- Un reader sin datos previos aparece con historial de ceros hasta acumular al menos una medición.
API: GET /api/diag/reader_latency. Devuelve un array con todos los readers conectados (tipo nc/mg/hw), su CAID, latencia media EMA y el array de historial de 20 posiciones.
Hit rate de resolución ECM
Barras proporcionales con el porcentaje de ECMs resueltas por cada vía desde el arranque del daemon: caché, lector local, red P2P, lector ocupado y denegadas. Útil para ajustar la configuración de ecm_multipath, el tamaño del caché o el número de peers activos.
API: GET /api/diag/stats. Devuelve: total, cache, local, net, busy, deny con sus respectivos porcentajes *_pct.
Eventos del sistema
Ring buffer de 200 eventos con timestamp, tipo e icono. Solo eventos relevantes para el usuario, sin ruido del log técnico:
- Canal con denegaciones acumuladas (cada 10): SID y contador.
- Lector saturado (cada 5 busy del mismo SID): identificación del cuello de botella.
- Peer conectado / desconectado: usuario e IP del peer.
- CW inválida rechazada (FakeCW detectada).
Los eventos se muestran en orden cronológico inverso (el más reciente primero) con color por tipo. API: GET /api/diag/events.
Coste en RAM: ~20 KB fijos (200 entradas × 100 bytes). Sin hilos adicionales ni polling interno.
⚙ Pestaña CSA
Control del motor de descifrado y todos los parámetros de CW/ECM/EMM. Los cambios se aplican en caliente pulsando "Aplicar Configuración CSA".
Módulos CSA
| Toggle | Default | Descripción |
|---|---|---|
| SoftCam (emulador) | ON | Activa el emulador de tarjeta por software usando SoftCam.Key. Cuando está activo, Candela puede descifrar sin tarjeta física los canales que tengan clave en el archivo. Al desactivarlo se liberan las claves de la RAM, los lectores emu/constcw desaparecen del dashboard y dejan de resolver ECMs. |
| DVBAPI | ON | Activa la interfaz de comunicación con el receptor DVB. Sin DVBAPI, el receptor no puede pedir CWs a Candela. El toggle detiene o arranca el socket DVBAPI en caliente sin reiniciar el daemon. |
| StreamRelay | ON | Activa el motor CSA SIMD para descifrado de streams TS en tiempo real (iDVB). Solo disponible cuando DVBAPI está activo - el toggle se desactiva automáticamente si DVBAPI está apagado. Campo enable_streamrelay en candela.json. |
DVBAPI & StreamRelay
| Campo | Descripción |
|---|---|
| Socket/Puerto DVBAPI | En Linux: socket Unix /tmp/camd.socket (Enigma2/VDR) o TCP. En Windows: solo TCP puerto 9000. |
| Puerto StreamRelay (iDVB) | Puerto donde el motor CSA SIMD escucha para descifrado de streams TS completos. Default: 17999. |
| Modo PMT | 0=Estándar (parseo PMT completo), 1=Rápido (sin parseo, solo ECM PID). Usar 0 salvo en receptores problemáticos. |
PID File (pidfile) | Ruta al archivo donde Candela escribe su PID al arrancar (ej: /var/run/candela.pid). Útil para scripts de init, systemd o supervisord. none = deshabilitar la comprobación de instancia única. Vacío = ruta por defecto (<dir_config>/candela.pid). |
Control de CW y ECM
| Toggle / Campo | Default | Descripción |
|---|---|---|
| CW Cycle Check | ON | Detecta CWs congeladas (repetidas) y ciclos anómalos donde ambas mitades de la CW cambian simultáneamente. Bloquea CWs inválidas antes de envíarlas al receptor. Recomendado siempre activo. |
| DoubleCheck (≥2 peers) | OFF | Requiere que al menos 2 peers distintos devuelvan la misma CW antes de aceptarla. Si hay discrepancia, espera una tercera CW para desempate por mayoría. Aumenta la latencia pero elimina CWs corruptas de peers poco fiables. CW Cycle Check tiene prioridad - si ya verificó la CW, DoubleCheck se omite. |
| Sin CRC check (global) | OFF | Desactiva la verificación CRC de la CW para todos los sistemas. Útil en algunos sistemas no estándar (algunos Viaccess y Nagra) que no respetan el CRC DVB. Usar con precaución - puede pasar CWs incorrectas. |
| Preferir tarjetas locales | ON | El motor HLS prioriza siempre lectores de tarjeta local (Hop 0) frente a peers remotos. Reduce latencia y carga en la red P2P. |
Timeout inactividad ECM (ecm_idle_timeout_h) | 0 | Desconecta automáticamente los peers que no han envíado ningúna ECM en el número de horas indicado. 0 = desactivado. Útil para limpiar peers que permanecen conectados sin consumir. Ver §27 del FAQ para más detalles. |
Control ECM / CW / EMM Avanzado
| Toggle | Default | Descripción |
|---|---|---|
| Reshare CW | ON | Cuando Candela recibe una CW resuelta de un upstream, la redistribuye a otros peers que también la solicitaron. Desactivar para convertir Candela en pure-client (solo consume, no redistribuye). |
| ECM DB (offline) | OFF | Guarda en disco (config/candela.ecmdb) las relaciones ECM→CW resueltas. Si el upstream cae, Candela puede responder ECMs conocidas desde la DB local sin necesidad de tarjeta ni peer. Penaliza ligeramente el rendimiento de escritura. |
| Bloquear EMM desconocidas | ON | Solo procesa EMMs de tipos que Candela reconoce para la tarjeta detectada. Las demás se descartan sin pasar al lector. Protege la tarjeta de comandos inesperados que la operadora podría usar para detectar uso en carsharing. |
| Log ECM detallado | OFF | Genera una línea de log por cada ECM recibida: CAID, SRVID, ProvID, hash, latencia y resultado. Muy útil para diagnosticar canales que no abren. Genera mucho volumen, usar solo para diagnóstico puntual. |
| Log CW detallado | OFF | Loguea cada CW aceptada o rechazada con el motivo: válida, FakeCW, DoubleCheck pendiente, CRC fallo. Muy verboso. Solo para debug de problemas específicos de CWs. |
| Log EMM | OFF | Loguea cada EMM procesada: tipo, CAID, resultado (aceptada/rechazada/ignorada) y si hubo actualización de entitlement. Útil para verificar que la tarjeta se actualiza correctamente. |
| Caché ECM activa | ON | Guarda en RAM las respuestas ECM→CW. Si otro cliente pide la misma ECM antes de que expire la CW, responde desde caché sin molestar al upstream. El tamaño máximo se controla con "Tamaño caché CW". |
| CacheEX (compartir caché) | OFF | Los peers intercambian entradas de caché proactivamente. Reduce latencia en redes de confianza. No recomendado con peers desconocidos. Con DoubleCheck activo, la seguridad mejora significativamente. |
Parámetros numéricos
| Campo | Default | Descripción |
|---|---|---|
| Tamaño caché CW (slots) | 2048 | Número máximo de entradas en la caché RAM. Cada entrada ocupa ~50 bytes. 2048 slots = ~100KB. |
| Límite ECM/s (ratelimit) | 4 | Máximo de ECMs por segundo por cliente. Evita que un cliente sature el servidor upstream. 0 = sin límite. |
| TTL caché offline (s) | 30 | Segundos que la CW en caché sigue siendo válida aunque el upstream esté caído. 0 = sin caché offline. |
| Timeout ECM (ms) | 5000 | Milisegundos máximos esperando una CW antes de intentar el siguiente peer disponible. |
MultiPID - Descifrado paralelo de todos los CA PIDs
Toggle multipid_mode en la pestaña CSA. Por defecto desactivado (comportamiento clásico: primer CA descriptor de la PMT).
Cuando está activo, Candela parsea todos los descriptores CA de la PMT (hasta 8) y lanza ECMs en paralelo a todos los sistemas CA. La primera CW válida se entrega al receptor. Los demás intentos se descartan en cuanto llega la primera respuesta.
Útil en canales con múltiples sistemas CA simultáneos, como plataformas cable/IPTV que emiten tanto Viaccess como Nagra en el mismo múltiplex. Si el sistema prioritario no tiene lector ni peer disponible, el secundario resuelve el canal automáticamente sin intervención del usuario.
QuickECM - Timeout de respuesta ECM por CAID
Tabla configurable en la pestaña CSA. Por defecto vacía: todos los CAIDs usan el timeout global/adaptativo (ETO + client_timeout).
Permite definir por CAID:
- Intervalo ECM (ms): período esperado entre ECMs del canal. Informativo para el watchdog.
- Timeout (ms): tiempo máximo de espera de CW para ese CAID. Si se alcanza, la ECM pendiente expira y se puede reintentar. Sobreescribe el timeout adaptativo para ese CAID específico.
0 en cualquier campo = usar comportamiento actual sin modificar. Útil para operadores con ciclo ECM muy rápido (<2s) o muy lento (>15s) que provocan timeouts prematuros o esperas innecesarias.
AES-128 IPTV - Descifrado de streams IPTV y OTT
El motor CSA de Candela ya soporta DVB-CISSA (AES-128-CBC con IV derivado del TS), AES-ECB, AES-CTR y auto-detección por sync byte. El módulo AES IPTV añade la capa de configuración de claves estáticas y el fetcher HTTP/HTTPS para el caso de uso IPTV.
Fichero candela.aeskeys
Formato de una línea por canal:
SRVID_HEX KEY_32HEX [IV_32HEX] [algo=auto|cissa|ecb|ctr|cbc0] # comentario
SRVID_HEX URL:https://keys.operador.com/canal.bin [algo=cissa]
SRVID_HEX auto # sin clave: usar pipeline ECM normal (explícito)| Campo | Descripción |
|---|---|
| SRVID_HEX | Service ID del canal en hexadecimal (el mismo que aparece en el Diagnóstico ECM). |
| KEY_32HEX | Clave AES-128 en 32 caracteres hex (16 bytes). Sin separadores. |
| IV_32HEX | Vector de inicialización opcional (32 hex = 16 bytes). Si se omite, se usa IV=0 o el IV derivado del TS según el algoritmo. |
| URL:http://... | URL de la que fetchear la clave. Se hace una petición HTTP GET al arrancar y cada vez que el daemon necesita la clave. Soporta HTTPS con OpenSSL. |
| algo= | auto (default, detecta por sync byte 0x47), cissa (DVB-CISSA AES-128-CBC con IV de TS), ecb (AES-128-ECB), ctr (AES-128-CTR para OTT), cbc0 (AES-128-CBC con IV=0). |
| auto | Sin clave configurada: el canal usa el pipeline ECM normal (P2P, lector local, NewCamd, MGcamd). Equivale a no tener entrada. |
Comportamiento si no hay clave
Si un canal no tiene entrada en candela.aeskeys, Candela lo trata exactamente como antes: solicita la ECM por la red P2P, el lector local o NewCamd/MGcamd. El módulo AES IPTV es una capa adicional, no un reemplazo del pipeline ECM.
Panel WebIF
La pestaña CSA incluye un panel de claves AES IPTV que muestra las entradas cargadas desde candela.aeskeys: SRVID, modo (static/url), algoritmo, estado de la clave (lista/pendiente) y URL si aplica. Un botón "Recargar fichero" recarga candela.aeskeys sin reiniciar el daemon. El endpoint es GET /api/config/aeskeys y POST /api/config/aeskeys/reload.
📸 Proxy IPTV multicast/unicast
Candela incluye un proxy HTTP compatible con la API de udpxy directamente en el daemon. Elimina la dependencia del proceso externo udpxy sin necesitar cambios en la configuración del STB.
Activación
En la pestaña CSA del WebIF, activa Proxy IPTV multicast/unicast y configura el puerto (por defecto 8088). O en candela.json:
"enable_iptv_proxy": 1,
"iptv_proxy_port": 8088
Formatos de URL soportados
| Formato | Descripción |
|---|---|
/udp/239.x.x.x:8208 | Multicast UDP estándar (mismo formato que udpxy) |
/udp/239.x.x.x | Multicast UDP sin puerto - usa 1234 por defecto |
/rtp/239.x.x.x:8208 | Multicast RTP - elimina header RTP variable (RFC 3550) |
/http://host/stream | Relay HTTP directo de stream unicast |
/?url=http://host/stream | Relay HTTP con parámetro URL |
Ejemplo de bouquet IPTV
Si el STB tiene en su lista de canales:
udp://@239.0.5.185:8208
Configura el STB para usar Candela como proxy udpxy y el STB pedirá:
http://ip_candela:8088/udp/239.0.5.185:8208
Candela une al grupo multicast, aplica descifrado AES-128 si hay clave en candela.aeskeys para ese stream, y reenvía el TS al STB.
Descifrado AES en proxy IPTV
Si existe una entrada en candela.aeskeys con el SRVID del stream, los paquetes TS se descifran antes de enviarse. No requiere configuración adicional - el descifrado es completamente transparente para el STB.
Estadísticas
Endpoint GET /api/iptv/streams. Campos por stream: grupo multicast, IP del cliente, nombre del canal, bytes enviados, bitrate en bytes/s y estado AES. La card de actividad IPTV/HLS aparece en el monitor del WebIF cuando hay streams activos.
🎥 Proxy HLS AES-128-CBC
Candela actúa como proxy entre el player y el servidor de streaming HLS. Los segmentos cifrados con AES-128-CBC se descifran en vuelo; el player recibe TS limpio sin necesitar soporte de descifrado propio.
Activación
En la pestaña CSA del WebIF, activa Proxy HLS AES-128-CBC y configura el puerto (por defecto 8089). O en candela.json:
"enable_hls_proxy": 1,
"hls_proxy_port": 8089
Cómo usarlo
Sustituye la URL del stream en el player:
| Original | Via proxy Candela |
|---|---|
http://stream.tv/live/playlist.m3u8 |
http://ip_candela:8089/http://stream.tv/live/playlist.m3u8 |
https://cdn.tv/ch/playlist.m3u8 |
http://ip_candela:8089/?url=https://cdn.tv/ch/playlist.m3u8 |
Candela descarga el manifiesto m3u8, reescribe las URLs de los segmentos para que pasen por el proxy con el IV correcto embebido, y descifra cada segmento antes de servirlo.
Gestión de claves AES
Candela busca la clave en este orden:
- En la caché de claves en memoria (por sesión, evita re-búsquedas)
- En
candela.aeskeyspor SRVID derivado de la URL del stream - Descargándola desde la URI del
#EXT-X-KEYdel manifiesto (HTTP o HTTPS)
Cuando se descarga una clave nueva, se guarda automáticamente en candela.aeskeys para futuras sesiones.
Detalles técnicos
| Característica | Implementación |
|---|---|
| IV por segmento | Explícito si IV=0x... en EXT-X-KEY; implícito = media_sequence + seg_index en big-endian de 16 bytes (RFC 8216 §5.2) |
| Padding | PKCS#7 validado byte a byte y eliminado tras descifrado |
| Descifrado | OpenSSL EVP_aes_128_cbc con AES-NI automático en CPU compatible |
| HTTPS claves | SSL_new/SSL_connect/SSL_read - sin verificación de cert (claves internas) |
| Chunked encoding | Decodificado in-place antes de procesar |
| Rotación de claves | Tabla key_range_t[] - cada rango aplica desde un segmento concreto |
| Detección m3u8 | Por extensión URL O por contenido (#EXTM3U al inicio del body) |
🔧 Pestaña Config
Configuración de lectores de tarjeta, cuentas de clientes y servidores upstream. Los cambios se guardan en config/candela.json al pulsar Guardar Config Completa.
Cards expandibles - Funcionamiento
Cabecera: label/IP, badges de flags activos (CW-Push, CacheOnly, etc.), badge estado (● Token / ● Online), servicios selecciónados separados por " | ".
Cuerpo: todos los campos de edición, campos específicos por CAS, stats en vivo.
+ Añadir: crea un item nuevo ya expandido para rellenar.
Tooltips: pasar el ratón sobre cualquier campo o badge muestra descripción.
Lectores Locales
Tarjetas físicas conectadas al equipo donde corre Candela. Soporta PC/SC (Windows/Linux), Phoenix/Dragon, y lector interno de decos Enigma2.
Sistemas CAS soportados
| CAS | CAIDs | Providers típicos | Campos extra |
|---|---|---|---|
| Nagravision 2/3 | 0x1800–0x18xx | Sky IT, Skylink, Movistar+, Canal Digital | RSAKey, BoxKey, NUID (opc) |
| CAK7/Merlin | 0x1811, 0x1813, 0x1856, 0x1861, 0x186A, 0x1884 | Canal+ FR, NC+ / Polsat, Tivùsat, HD+ | RSAKey, BoxKey, CWEKey (obligatoria) |
| NDS/Videoguard | 0x090x, 0x09xx | Sky DE (098C/098D), Sky UK, Foxtel, DirecTV | BoxID (obligatorio), RSAKey (opc) |
| Viaccess | 0x05xx | Canal+ FR / CanalSat, TNT Sat, Bis TV | Sin claves adicionales |
| Irdeto | 0x06xx | Ziggo, Canal Digitaal, UPC | Sin claves adicionales |
| Betacrypt | 0x1702, 0x1722 | Kabel Deutschland / Sky DE (tunneling Nagra) | Sin claves adicionales |
| SECA/Mediaguard | 0x0100–0x01xx | Canal+ FR, CanalSat, AB Sat (legacy) | Sin claves adicionales |
| Conax | 0x0Bxx | Viasat Nordic, Canal Digital, Telenor | Sin claves adicionales |
| Cryptoworks | 0x0Dxx | Tele Columbus, EWE TEL, KDG (cable DE) | Sin claves adicionales |
| TongFang | 0x4A02, 0x4AEE | IPTV/Satélite China, StreamGuard | Calibration SN (opc) |
| JET | 0x5B00 | Indonesia, Tailandia, Asia | Authorize ID (opc) |
| DRE-Crypt | 0x4AE0, 0x4AE1 | Tricolor TV, NTV+, Raduga TV (Rusia/CIS) | BoxID |
Campos de configuración del lector
| Campo | Descripción |
|---|---|
| Label | Nombre descriptivo. Se autorrellena al selecciónar el tipo CAS. |
| Tipo CAS | Sistema de acceso condicional. Ver tabla de CAS soportados. |
| Protocolo / Dispositivo o Ruta del archivo | internal, pcsc, mouse, smartreader, emu, constcw, mosc. Para lectores físicos usar /dev/sci0 o /dev/ttyUSB0. Para emu o constcw, especificar la ruta al archivo (ej: /config/constant.cw). |
| MHz / Card MHz | Frecuencia del reloj del lector y de la tarjeta. Default: 368/368. |
| Max paralelo | Máximo de servicios simultáneos. 0 = ilimitado. CAK7/NDS con slot limit: 1–4. |
| RSA Key | Nagra 2/3. Clave RSA de la tarjeta (64 bytes hex). |
| BoxKey | Nagra. BoxKey del receptor (16 bytes hex). |
| BoxID | Nagra/NDS/DRE. ID del receptor (8 hex chars). Obligatorio en NDS. |
| NUID | Nagra CAK7. NUID de la tarjeta. Opcional según provider. |
| CWEKey | Nagra CAK7/Merlin. CW Encryption Key (16 bytes hex). Obligatoria en Sky/Canal+ modernos. Sin ella los canales CAK7 no abren. |
| Fechas NDS | Año/mes base para calcular fechas de expiración de tiers NDS. Sky DE V15+: 2020. Mayoría: 1997. |
| Calibration SN | TongFang3. Serial de calibración del provider. |
| Authorize ID | JET. ID de autorización del provider asiático. |
Cuentas de Clientes
Usuarios que pueden conectarse a este Candela como clientes P2P. Cada cuenta tiene usuario/contraseña y opciones de acceso.
__local__: Candela reserva este usuario para uso propio
(DVBAPI socket, StreamRelay/iDVB, emulador SoftCam). No aparece en la lista de cuentas, no depende
de IP, tiene acceso total sin restricciones y no consume un salto de red. No hay que crearlo ni configurarlo.
visor: Para tu receptor DVB o IPTV player,
crea una cuenta visor con CW-Push ✓,
CacheOnly ✗, NoCache ✗, EMM ✗.CacheOnly activado lo bloquea - solo obtiene CWs ya cacheadas, nunca inicia peticiónes ECM reales.
| Campo | Descripción |
|---|---|
| Servicios | Multi-select. Grupos de canales a los que esta cuenta tiene acceso. Vacío = acceso total. Los grupos se definen en config/candela.services. |
| EMM | Permitir que este cliente reciba EMMs de actualización de tarjeta. |
| CW-Push | Enviar CWs proactivamente a este cliente sin esperar su petición ECM. |
| CacheOnly | Este cliente solo puede usar la caché - no genera ECMs reales al upstream. |
| NoCache | Este cliente siempre resuelve en vivo, no usa la caché. |
| No CacheEX | No intercambiar datos de caché con este cliente. |
Servidores Upstream
Candelas remotos a los que este nodo se conecta como cliente para pedir CWs. Funciona como el "server" en CCcam/Newcamd pero con el protocolo Candela cifrado.
| Campo | Descripción |
|---|---|
| IP / Puerto | Dirección del servidor Candela remoto. |
| Usuario / Contraseña | Credenciales de la cuenta en el servidor remoto. |
| Servicios | Multi-select. Filtrar qué grupos de canales se solicitan a este servidor. Vacío = pedir todo. |
| CW-Push | Aceptar CWs proactivas de este servidor. |
| CacheOnly | Solo usar la caché de este servidor. |
| NoCache | No intercambiar caché con este servidor. |
🔬 Pestaña Forense ACF (Arsenal Forense Candela)
Herramientas de análisis e investigación para técnicos. A diferencia del Monitor (diagnóstico pasivo), el Forense permite intervención activa y análisis dirigido.
Las herramientas forenses están organizadas en sub-pestañas para no saturar la pantalla:
| Sub-pestaña | Herramientas |
|---|---|
| Inspectores | Live CW Inspector, Inspector Payload ECM |
| Bóvedas | EMM Vault, Timeline Forense ECM |
| Calculadoras | Nagra Key Calculator, Virtual MOSC |
| Laboratorio | APDU Fuzzer, ECM Simulator/Fuzzer, CW Brute-Force |
Live CW Inspector
Inspecciona CWs individuales sospechosas: introduce una CW en hex y Candela analiza su estructura, calcula su CRC, comprueba todos los patrónes de FakeCW y muestra si sería aceptada o rechazada y por qué motivo exacto (capa 1/2/3).
Inspector de Payload ECM
Disección byte a byte del payload de una ECM: cabecera APDU, nanos identificados, campos de control de acceso, CRC. Permite comparar estructuras ECM entre distintos providers para identificar variantes.
Timeline Forense ECM
Vista cronológica de eventos ECM/CW con resolución de milisegundos. Muestra la secuencia temporal de peticiónes, respuestas, timeouts y cambios de CW para diagnosticar canales que intermitentemente pierden el descifrado.
EMM Vault
Captura y almacena las EMMs recibidas de la red DVB. Permite analizarlas offline para entender qué comandos envía la operadora a las tarjetas. Imprescindible para investigar actualizaciónes de tarjeta o intentos de bloqueo.
Nagra Key Calculator
Dado el RSAKey y el BoxKey de una tarjeta Nagravision 2/3 (obtenidos del decodificador), calcula los parámetros derivados que algunos providers solicitan: NUID, ECMKey, CWEKey y BoxKey extendida. Los cálculos son heurísticos - válidos para la mayoría de providers pero algunos usan esquemas propietarios adicionales.
Virtual MOSC
Clon virtual completo de una tarjeta física en memoria RAM: CAID, ProvID, UA, tiers, fechas de expiración, ATR y todas las claves CAS (RSAKey, BoxKey, CWEKey, etc.). Una vez clonada, la tarjeta virtual puede:
- Resolver ECMs como si fuera la tarjeta física - actúa como lector virtual en el pool de Candela.
- Editar tiers y fechas via
/api/forensics/mosc_edit: modificar suscripciones activas, fechas y configuración del clon para pruebas de compatibilidad y análisis forense. - Editar claves CAS directamente sobre el clon: útil para probar variantes de clave, reparar una clave corrompida o cargar claves actualizadas obtenidas por otros medios.
El clon opera completamente en RAM y no modifica la tarjeta física original. Múltiples clones pueden coexistir simultáneamente con configuraciónes distintas.
reader_active=1, Candela registra el clon como lector virtual y alimenta automáticamente los EMMs del stream DVB - el descifrado se normaliza en cuanto completa el ciclo de EMMs (habitualmente 30–120s según operadora).Endpoints: /api/forensics/mosc_clone, /api/forensics/mosc_state, /api/forensics/mosc_edit, /api/forensics/mosc_emm.
APDU Fuzzer & Profiler
Envía comandos APDU ISO-7816 arbitrarios directamente a un lector de tarjeta local y muestra la respuesta. Permite explorar los comandos que acepta una tarjeta, medir tiempos de respuesta y diagnosticar problemas de comunicación con el lector.
ECM Simulator / Fuzzer
Genera ECMs sintéticas con campos configurables (CAID, SRVID, nano flags, longitud) y las inyecta en el flujo de procesamiento de Candela. Permite probar el comportamiento del sistema con ECMs malformadas, fuera de rango o de providers desconocidos sin necesidad de una fuente DVB real. Endpoint: /api/forensics/ecm_sim.
CW Brute-Force
Herramienta de análisis de CWs: dado un fragmento conocido del stream cifrado y la CW candidata, verifica si la CW descifra correctamente usando el motor CSA SIMD nativo. Útil para investigar CWs parciales o verificar implementaciónes de descifrado.
🔮 CW Predictor (CWP)
GET /api/monitor/cw_cycles.Ubicación en el WebIF: no es una pestaña independiente. La tabla del CW Predictor aparece al final de la pestaña Monitor, después del ECM Inspector.
El CW Predictor aprende el ciclo de vida de las CWs por canal y lanza la petición al upstream antes de que la CW actual expire. El resultado es zapping instantáneo sin pantalla negra incluso con upstreams lentos.
Cómo funcióna
Para cada canal activo (CAID × SRVID), CWP mantiene un perfil con:
- cycle_ms - ciclo de CW medido en milisegundos (EWMA con α=0.25, actualización continua)
- last_cw_ts - timestamp de la última CW entregada
- cw_last[16] - última CW recibida (para detectar cambio de criptoperíodo)
- samples - número de ciclos medidos (mínimo 3 para activar prefetch)
- prefetch_armed / prefetch_fired - estado del prefetch en curso
El watchdog (cwp_tick()) corre cada ~500ms. Cuando detecta que ha pasado el 80% del ciclo esperado y aún no se ha recibido la nueva CW, lanza automáticamente la ECM al upstream sin esperar a que el demux lo solicite.
Límites y constantes
| Constante | Valor | Descripción |
|---|---|---|
| CWP_MAX_CHANNELS | 128 | Canales simultáneos con perfil activo. |
| CWP_MIN_SAMPLES | 3 | Muestras mínimas antes de activar prefetch. |
| CWP_PREFETCH_PCT | 80% | Porcentaje del ciclo tras el que se lanza el prefetch. |
| CWP_MIN_CYCLE_MS | 4000 ms | Ciclos menores se descartan (anti-ruido). |
| CWP_MAX_CYCLE_MS | 30000 ms | Ciclos mayores de 30s se descartan. |
API
| Endpoint | Descripción |
|---|---|
GET /api/monitor/cw_cycles | JSON array con todos los canales activos: CAID, SRVID, cycle_ms (EWMA), muestras, estado prefetch, timestamp última CW. Disponible en la pestaña Monitor del WebIF. |
Config
| Campo | Descripción |
|---|---|
| enable_cw_predictor | Activa el CW Predictor (defecto: 1). Reducir a 0 solo en sistemas sin DVBAPI ni clientes CW-push. |
✏ Pestaña Editor
Gestión de los archivos de configuración de datos que Candela lee en tiempo real.
SoftCam.Key Manager
Editor del archivo config/SoftCam.Key. Contiene las claves en texto plano para el emulador. Formato compatible con SoftCam estándar. Se puede recargar en caliente sin reiniciar usando "Recargar SoftCam".
FakeCW Blacklist
Editor del archivo config/fakecws. Lista de patrónes de CW que se rechazan siempre independientemente de la heurística. Una línea por CW en hex de 16 bytes.
Services
Editor del archivo config/candela.services. Define grupos de canales por CAID:SRVID para asignar permisos por cuenta. Formato similar a ncam.services.
SrvID
Editor del archivo config/candela.srvid. Tabla de resolución CAID:SRVID → nombre de canal. Permite que el WebIf y los logs muestren nombres legibles en lugar de IDs numéricos.
ProvID
Editor del archivo config/candela.provid. Tabla de resolución CAID:ProvID → nombre de proveedor. Complementa a SrvID: donde SrvID resuelve el canal, ProvID resuelve el nombre del operador/proveedor para ese CAID y ProvID concreto.
candela.aeskeys (Claves AES IPTV)
Editor del archivo candela.aeskeys. Contiene las claves AES-128 para descifrado de streams IPTV y OTT. Una línea por canal. Ver también el panel de Claves AES IPTV en la pestaña CSA.
Formato: SRVID_HEX CLAVE_32HEX [IV_32HEX] [algo=auto|cissa|ecb|ctr|cbc0] o SRVID_HEX URL:https://servidor/key. Usar * como SRVID para definir una clave global que se aplique a cualquier canal sin entrada específica. Si no hay entrada para un canal, el pipeline ECM normal resuelve la CW.
candela.prio (Motor de prioridad)
Editor del archivo candela.prio. Define reglas de enrutamiento ECM por CAID:PROVID[:SRVID]. Dos tipos de regla:
- ALLOW - Autoriza la ECM. Si existe alguna regla ALLOW activa, las ECMs que no coincidan con ningúna son rechazadas (modo lista blanca). Útil para limitar qué sistemas de acceso condicional se descifran.
- SKIP - Descarta la ECM incondicionalmente, sin consultar lector ni red. Útil para bloquear proveedores o canales concretos.
Formato: ALLOW|SKIP CAID:PROVID[:SRVID] # comentario. Comodines: omitir SRVID aplica la regla a cualquier servicio del CAID:PROVID; PROVID 000000 coincide con cualquier proveedor del CAID.
Las reglas se evalúan antes que los filtros por usuario. Una ECM SKIPpeada se descarta para todos los clientes, incluidos los locales (DVBAPI). El archivo se puede editar directamente desde el WebIF en la pestaña Editor o a través del fórmulario de la pestaña Diagnóstico, donde además pueden aplicarse las sugerencias del modo preview como reglas ALLOW/SKIP con un solo clic.
📋 Pestaña Log
Consola de log en tiempo real. Muestra los últimos mensajes del proceso Candela. Incluye filtrado por nivel (DEBUG, INFO, WARNING, ERROR). Los logs en consola pueden silenciarse con "Silent Mode" en Mantenimiento - en ese caso solo se escriben en el fichero de log si está configurado.
🛠 Pestaña Mantenimiento
Todas las secciones se guardan con el botón único "Guardar Config" situado al final del tab. No hay botónes por sección. Orden de secciones: WebIF y Sistema → Red P2P - Identidad y Acceso → Servidor NewCamd/MGcamd → Seguridad y Alertas → Transporte y Anti-DPI (CTC + AMPE) → Credenciales WebIF → TLS.
WebIF y Sistema
Parámetros del servidor web y comportamiento general. Cambios via /api/config/global.
| Campo | Default | Descripción |
|---|---|---|
Puerto WebIf (web_port) | 8080 | Puerto HTTP/HTTPS del WebIf. |
IPs Permitidas (http_allowed) | 127.0.0.1,192.168.0.0/16 | Lista de IPs/rangos separados por coma que pueden acceder al WebIf. |
Silent Mode (silent_mode) | 0 | No escribe en la consola. Los logs van solo a fichero si está configurado. |
Forense ACF (enable_forensics) | 0 | Activa/desactiva toda la pestaña Forense y el módulo de captura de EMMs. |
Chat P2P (enable_p2p_chat) | 0 | Activa el panel de mensajería privada P2P. Requiere que ambos peers tengan R31+. |
WebIf (enable_webif) | 1 | Activa o desactiva completamente el servidor web. Desactivar si se usa Candela en modo headless. |
🌐 Red P2P - Identidad y Acceso
Identidad del nodo en la red P2P y control de acceso. Cambios via /api/security/advanced.
| Campo | Default | Descripción |
|---|---|---|
Puerto(s) P2P (port + extra_ports) | 15000 |
Puerto(s) TCP donde Candela escucha conexiónes P2P. El campo acepta un puerto o varios en un único campo con tres formatos combinables (máx. 9 puertos en total): • Simple: 15000• Lista: 15000,18000,19000• Rango: 15000,18000-18005El primer puerto es el principal; el resto se arrancan como listeners adicionales en hilos independientes. |
| NodeID | Aleatorio | Identificador único de este nodo en la red P2P (64 bits hex). El botón ⟳ genera uno nuevo al instante con crypto.getRandomValues() sin necesidad de reiniciar. El campo también es editable manualmente (solo caracteres hex 0-9/A-F). |
Nombre de operador (operator_name) | "" | Nombre visible en la red Candela vía Node Gossip (máx. 32 caracteres). Aparece en el panel Nodos de otros peers. Dejar vacío para permanecer anónimo. |
Ghost UA (ghost_ua) | "" | Bytes hexadecimales (ej: 00 11 22 33 AA BB) que Candela incluye como User-Agent falso en el protocolo P2P. Imita el patrón de otro softcam para confundir sistemas DPI. Dejar vacío = identificador genérico anónimo. |
IPs P2P permitidas (p2p_allowed) | "" | Lista de IPs/rangos que pueden conectarse como peers P2P. Vacío = sin restricción. Formato: 192.168.1.0/24,10.0.0.1. |
Máx. conexiónes por IP (p2p_max_conn_per_ip) | 0 | Máximo de conexiónes P2P simultáneas desde la misma IP. 0 = sin límite. Protege contra floods de conexión. |
🚨 Seguridad y Alertas
Control del sistema anti-brute-force, alertas automáticas y registro de actividad. Cambios via /api/security/alerts.
| Campo | Default | Descripción |
|---|---|---|
Failban (enable_failban) | 1 | Activa el bloqueo automático de IPs con fallos de autenticación reiterados. Si se desactiva, los eventos de seguridad siguen registrándose pero no se bloquea ningúna IP automáticamente. |
Alertas por umbral (alerts_enabled) | 0 | Activa las alertas visuales en el panel cuando se superan los umbrales configurados. |
Umbral intentos/min (alert_fail_rate) | 5 | Número de intentos de autenticación fallidos por minuto que dispara la alerta de brute-force. |
Umbral latencia (alert_latency_ms) | 2000 | Latencia media en ms por encima de la cual se activa la alerta de rendimiento. |
Audit Log (enable_audit_log) | 0 | Activa el registro de eventos de seguridad: conexiónes, autenticaciónes fallidas, bans. Se visualiza en el panel lateral (pestaña 🔔 Alertas). |
Config Log (enable_config_log) | 0 | Loguea cada cambio de configuración con timestamp e identificación del campo modificado. |
Gestión de peers - Permaban / Tempban
Desde el panel lateral (pestaña Alertas) se puede bloquear una IP permanentemente o temporalmente. Los peers baneados no pueden conectarse aunque tengan credenciales válidas.
Transporte - CTC (Fake TLS 1.3)
Parámetros del sistema de camuflaje de protocolo. Cambios via /api/config/csa.
| Campo | Default | Descripción |
|---|---|---|
Pulse Masking (enable_pulse_masking) | 1 | Inyecta tráfico de relleno aleatorio para romper la firma temporal del cardsharing (el latido de 10s del criptoperíodo DVB). Ver sección CPM. |
Decoy Port (enable_dpm) | 1 | El puerto P2P responde con una página nginx falsa a escáneres HTTP. Ver sección DPM. |
SNI (ctc_sni) | "" | Nombre de dominio CDN usado en el SNI del ClientHello TLS. Vacío = selección aleatoria de un pool de CDNs reales en cada sesión. |
Prioridad de red (net_prio) | 0 | Prioridad SO para los sockets P2P (0–20). 0 = sin modificar. Útil en routers con QoS para priorizar el tráfico Candela. |
AMPE - Multi-Path ECM (ecm_multipath) | 3 | Peers consultados en paralelo por ECM. 0 = todos. 1 = un peer (clasico). N = top-N por score. Sin límite superior. Ver sección AMPE. |
Límite hop de tarjeta (card_hop_limit) | 0 | Hop máximo aceptado en CMD_CARD_MAP de peers. 0 = sin límite. 1 = solo hop 0-1. N = hasta N saltos. Ver sección AMPE. |
Credenciales WebIF
Permite cambiar el usuario y la contraseña del WebIf en caliente sin reiniciar. Requiere introducir la contraseña actual como verificación. Tras el cambio, todas las sesiones activas se inválidan y el navegador pide autenticación de nuevo. Se guarda en config/candela.json como http_user y http_pwd.
| Campo | Descripción |
|---|---|
| Nuevo usuario | Nuevo nombre de usuario para el WebIf. Si se deja vacío, se conserva el actual. |
| Contraseña actual * | Contraseña actual (obligatoria para autorizar el cambio). Se verifica en tiempo constante para evitar oráculos de timing. |
| Nueva contraseña * | Nueva contraseña. Se aplica inmediatamente al proceso en memoria y se persiste en disco. |
| Confirmar contraseña | Confirmación de la nueva contraseña. El frontend válida que coincidan antes de envíar. |
TLS / HTTPS
Genera un certificado X.509 auto-firmado RSA-2048 SHA-256 válido 365 días usando la librería OpenSSL ya enlazada (sin dependencia de openssl en PATH). El certificado se guarda en config/candela.crt y la clave privada en config/candela.key. Tras reiniciar Candela, el WebIf arranca en HTTPS si libmicrohttpd tiene soporte GnuTLS.
config/candela.crt en el almacén de certificados de confianza del sistema/navegador.Chat P2P
Cuando enable_p2p_chat=1, aparece el panel de mensajería en Mantenimiento. Características:
- Protocolo:
CMD_MSG_SEND (0x20)/CMD_MSG_ACK (0x21). Solo funcióna entre peers directamente conectados (sin relay). Si el peer no está conectado, el envío falla. - Cifrado: ChaCha20-Poly1305 sobre el canal P2P ya autenticado (ECDH X25519). Los mensajes no se almacenan en disco - solo en RAM (ring buffer 256 slots). Al reiniciar, se borran.
- Tamaño: hasta 480 bytes de texto por mensaje.
- Requisito: ambos peers deben tener R31 o posterior.
- API:
POST /api/messages/send(destino + texto),GET /api/messages(lista).
Reiniciar Servidor
Reinicia el proceso Candela en caliente. En Linux usa execv() (reemplaza el proceso con los mismos argumentos). En Windows usa CreateProcess() para lanzar un nuevo proceso antes de terminar el actual. El WebIf detecta la reconexión automáticamente (~3 segundos).
Backup / Restauración
Descarga todos los archivos de configuración en un ZIP, o restaura desde uno previamente descargado.
🔐 Protocolo P2P Candela
Handshake v2 - ECDH-first
En el Protocolo v2 (R35+), el intercambio ECDH X25519 se realiza antes de envíar las credenciales. El servidor rechaza cualquier CMD_HELLO sin ECDH previo - las credenciales nunca viajan bajo la clave bootstrap conocida (0x42×32).
1. Cliente ──[bootstrap key]──► CMD_ECDH_INIT (pubkey X25519, 32 bytes)
2. Servidor ──[bootstrap key]──► CMD_ECDH_RESP (pubkey X25519, 32 bytes)
════ Clave ECDH efímera activa ════
3. Cliente ──[ECDH key]──► CMD_ECDH_ACK
4. Cliente ──[ECDH key]──► CMD_HELLO (usuario + contraseña)
5. Servidor ──[ECDH key]──► CMD_HELLO_ACK
6. Cliente ──[ECDH key]──► CMD_CARD_MAP, CMD_NODE_INFO, mailbox
════ Sesión autenticada ════
Nonce anti-colisión
El nonce ChaCha20 de 12 bytes usa un contador monotónico por peer (tx_nonce_ctr uint64_t, incrementado en cada proto_send_packet). Los primeros 8 bytes del nonce aleatorio se XORean con este contador en big-endian, garantizando unicidad absoluta sin depender de la suerte probabilística (birthday paradox). Se resetea a 0 en cada reconexión.
Capas del protocolo
| Capa | Tecnología | Función |
|---|---|---|
| Transporte | TCP | Conexión persistente con reconexión automática. |
| Compresión | LZ4 | Compresión de alta velocidad antes del cifrado. Reduce el tamaño del tráfico ~40%. |
| Cifrado | ChaCha20-Poly1305 (OpenSSL) | Cifrado simétrico por sesión. Clave de sesión negociada via handshake ECDH efímero. |
| Autenticación | HMAC + NodeID | Verifica que el peer es un Candela legítimo con credenciales válidas. |
| Padding | Aleatorio | Bytes de relleno aleatorios en cada paquete para impedir identificación por tamaño. |
| Jitter | 50–300ms estocástico | Retraso aleatorio en paquetes de descubrimiento para romper correlación temporal DPI. |
Comandos del protocolo (CMDs)
| CMD | Nombre | Descripción |
|---|---|---|
0x01 | CMD_AUTH | Handshake de autenticación. Intercambia credenciales y negocia clave de sesión. |
0x02 | CMD_ECM_REQ | Solicita la CW para una ECM específica (hash MD5 de 16 bytes + datos ECM). |
0x03 | CMD_CW_RESP | Respuesta con la CW resuelta. Incluye la CW (16 bytes) + hash de la ECM correspondiente. |
0x05 | CMD_STATUS | Ping/pong de keepalive y estado del peer (canal visionando, latencia media). |
0x09 | CMD_CARD_MAP | Descubrimiento Ciego: anuncia qué CAIDs/ProvIDs puede resolver este nodo (Hop 0 = local, Hop 1+ = reshare). Nodos virtuales sin tarjeta física anuncian los hops de sus upstream. Byte HOP v2 (R35): bit 7 = no_reshare, bits 0-6 = distancia. No incluye UA ni datos de tarjeta. Capacidad máxima: 1024 pares CAID:PROVID por nodo (ampliado en R39 para ficheros SoftCam grandes). El lector EMU anuncia los pares reales del fichero SoftCam.Key usando los CAIDs estándar DVB por sistema CAS. |
0x0A | CMD_CW_PUSH | Envío proactivo de CW sin esperar petición ECM (CW-Push). |
0x0B | CMD_CACHE_SHARE | CacheEX: compartir entradas de caché con el peer. |
0x0C | CMD_SESSION_CHALLENGE R29 | Servidor envía nonce[32]+ts[8]. Inicio del handshake de token rotativo anti-sharing. |
0x0D | CMD_SESSION_RESPONSE R29 | Cliente responde con HMAC-SHA256(SHA256(pass+nodeid), nonce||ts)[32]. |
0x0E | CMD_SESSION_REVOKE R29 | Desconexión silenciosa si el HMAC no coincide o el token ha expirado. |
0x10 | CMD_ECDH_INIT R30 | Inicia PFS: el iniciador envía su clave pública X25519 efímera (32 bytes). |
0x11 | CMD_ECDH_RESP R30 | El receptor responde con su clave pública X25519 efímera (32 bytes). |
0x12 | CMD_ECDH_ACK R30 | Confirmación de PFS establecida. A partir de aquí se usa la clave derivada ECDH. |
0x20 | CMD_MSG_SEND R31 | Mensaje privado P2P cifrado. Payload: longitud (2B) + mensaje UTF-8. |
0x21 | CMD_MSG_ACK R31 | Acuse de recibo del mensaje. Confirma entrega al peer destino. |
Motor HLS (Heuristic Latency Scoring)
Cuando llega una ECM, el motor HLS decide a qué peer envíarla basándose en la puntuación compuesta de cada peer:
- Hop: peers con Hop 0 (tarjeta local) tienen máxima prioridad.
- Latencia media: peers con menor latencia histórica se prefieren. Score =
(avg_latency / factor_exactitud) × penalización_miss_rate. - Exactitud de CAID: coincidencia exacta CAID+ProvID puntúa mejor que coincidencia parcial.
- Affinity: si un peer resolvió recientemente el mismo SRVID, recibe un bonus ×4 (mismo canal = misma tarjeta).
- FakeCW rate: peers que han envíado FakeCWs reciben penalización progresiva hasta
hls_penalty_until. - Disponibilidad de CAID: solo se consultan peers que anunciaron soporte para ese CAID via CMD_CARD_MAP.
Con ecm_multipath=2 o =3 (AMPE), el motor seleccióna el top-N de peers con menor score y envía la petición ECM a todos en paralelo en el mismo tick del watchdog. La primera CW válida gana; los demás actualizan igualmente su score con sus tiempos reales. Ver sección AMPE.
🗝 SoftCam Emulator
Descifra canales por software usando claves almacenadas en config/SoftCam.Key, sin necesidad de tarjeta física. Funciona como fallback cuando no hay peers disponibles o como fuente primaria en instalaciones sin tarjeta.
Sistemas soportados
Formato SoftCam.Key
Formato estándar compatible con NCam/OSCam. Ejemplo:
F 01231FFF 00 1122334455667788
Donde: F=Tipo de clave (F=BISS), 01231FFF=Identificador (SID+PID), 00=KeyIndex, seguido de la clave en hex. Las claves se cargan en memoria al arrancar y son consultables desde el Monitor.
SSSSPPPP, donde SSSS es el Service ID (SID) y PPPP es el PMT/Video PID.
Nota interna: Candela es tolerante y aplica una máscara al PID, por lo que el descifrado funciónará siempre que el SID sea correcto (ej: 01230000).
constcw apuntando a tu archivo constant.cw. Esto mapeará el CAID:SRVID de forma nativa con rendimiento <1ms.
📺 DVBAPI & StreamRelay
DVBAPI
Interfaz estándar para que receptores DVB (Enigma2, VDR, Tvheadend, DVBViewer) soliciten descifrado de canales a Candela. Candela actúa como una "cam virtual".
| Plataforma | Configuración |
|---|---|
| Enigma2 (Linux) | Socket Unix /tmp/camd.socket o TCP localhost:9000. Candela reemplaza a OSCam/NCam/CCcam. Asegúrate de detener cualquier otro softcam para evitar conflictos por el control del socket. |
| VDR (Linux) | Plugin vdr-plugin-sc o similar. TCP localhost:9000. |
| Tvheadend (Linux/Windows) | Configurar CAM en Tvheadend como "External CA". TCP localhost:9000. |
| Windows (DVBViewer, etc.) | Solo TCP. Puerto 9000 por defecto. |
StreamRelay (iDVB)
Motor de descifrado CSA en tiempo real para streams TS completos. Usa instrucciones SIMD/AVX2 nativas para máximo rendimiento. Escucha en 127.0.0.1:17999 por defecto. Permite descifrar streams directamente sin pasar por el receptor DVB.
💾 Caché CW & ECM DB
Caché CW (RAM)
Las CWs resueltas se almacenan en una tabla hash en RAM indexada por el hash MD5 de la ECM. Cuando llega una ECM ya conocida, Candela responde en microsegundos sin consultar a ningún peer. El tamaño máximo es configurable (default: 2048 slots). Las entradas expiran automáticamente cuando la CW ya no es válida (una CW de DVB dura ~10 segundos).
ECM DB (disco)
Cuando está activo, guarda permanentemente las relaciones ECM→CW en el archivo config/candela.ecmdb. Permite responder ECMs conocidas incluso si el upstream está caído y la caché RAM ya expiró. Funciona como el module-emulator-ecmdb.c de NCam. Útil en instalaciones con upstreams poco fiables.
CacheEX
Extensión de caché P2P: los peers comparten entradas de caché entre sí. Cuando un peer resuelve una ECM, la entra en la caché de todos los peers conectados que tengan CacheEX activo. Reduce la latencia media en redes donde múltiples nodos ven los mismos canales.
🚫 Detección FakeCW
Candela implementa 3 capas independientes de detección de CWs falsas o corruptas. Una CW rechazada se descarta silenciosamente - no se envía al receptor DVB ni se guarda en caché.
Capa 1: Blacklist estática
Archivo config/fakecws editable desde la pestaña Editor. Contiene patrónes de CW conocidos como falsos (CWs de prueba de operadoras, patrónes de NCam, etc.). La comprobación es O(1) - búsqueda en tabla hash.
Capa 2: Heurística estructural
Analiza la estructura de la CW sin necesidad de contexto de canal. Detecta patrónes que nunca aparecen en CWs legítimas:
- Entropía baja (bytes muy repetidos).
- Mitades even/odd idénticas.
- 14+ bytes con el mismo valor (0x00, 0xFF, 0xAA, 0xCC, 0xF0).
- Secuencias incrementales o decrementales.
- Mitad even/odd con un único byte distinto.
Capa 3: Heurística dinámica
Analiza el comportamiento temporal de la CW en su contexto:
- Hop ≥ 2 + latencia < 80ms: imposiblemente rápido para una CW real pasando por 2 saltos. Indica un peer que responde sin resolver realmente.
- Ciclo SM < 6s: si dos CWs del mismo CAID:SRVID llegan con menos de 6 segundos de diferencia, una de las dos es falsa (el ciclo real de DVB es ≥10s).
✅ DoubleCheck CW
Sistema de verificación por consenso inspirado en el parche OSCam r11890+ de mejora del doublecheck. Requiere confirmación de múltiples peers antes de aceptar una CW.
Flujo de decisión
| Estado | Acción |
|---|---|
| CW Cycle Check ya verificó (estado 0x7F) | DoubleCheck se omite. La CW se acepta directamente. |
| Primera CW de un peer | Se guarda en cw_dc[0]. La CW queda pendiente - no se envía al receptor. |
| Segunda CW de un peer diferente, idéntica | Verificada (0x7F). La CW se acepta y se envía. |
| Segunda CW de un peer diferente, distinta | Se guarda en cw_dc[1]. Se espera una tercera CW para desempate. |
| Tercera CW coincide con cw_dc[0] | CW-A gana por mayoría. La CW-B (del peer2) queda marcada como sospechosa. |
| Tercera CW coincide con cw_dc[1] | CW-B gana por mayoría. La CW-A (peer1) queda marcada como sospechosa. |
| Tercera CW distinta de ambas | Sin consenso. Se espera más CWs. |
🔒 TLS / HTTPS
Generación de certificado
Candela genera un certificado X.509 auto-firmado RSA-2048 con SHA-256 usando la librería OpenSSL que ya viene enlazada en el binario. No requiere que openssl esté instalado en el sistema.
Archivos generados: config/candela.crt (certificado público) y config/candela.key (clave privada). La clave privada nunca sale del proceso - no se envía por red ni se registra en logs.
Activar HTTPS
- Ir a Mantenimiento → TLS / HTTPS → "Generar certificado auto-firmado"
- Candela guarda el certificado y actualiza config.json
- Reiniciar Candela (botón en Mantenimiento o manualmente)
- Acceder por
https://ip:8080
Requisito TLS en libmicrohttpd
Para que HTTPS funcióne, la librería libmicrohttpd debe haber sido compilada con soporte GnuTLS (--enable-https). En MSYS2: pacman -S mingw-w64-x86_64-libmicrohttpd. Si la lib no tiene soporte TLS, Candela arranca en HTTP y el log indica el motivo.
🧅 SOCKS5 / Tor / I2P
Candela soporta dos niveles de proxy para tunelizar conexiónes P2P salientes: un Proxy Universal global (nuevo, recomendado) y un proxy por-servidor (legado, por compatibilidad). Ambos permiten usar Tor, I2P o cualquier proxy SOCKS sin cambios en el protocolo.
Proxy Universal (global)
Disponible en Config → Proxy Universal - SOCKS4 / SOCKS5 / Tor / I2P. Se aplica a todas las conexiónes P2P salientes que no tengan un proxy por-servidor configurado.
- Sin proxy (directo)
- SOCKS5
- SOCKS4
- Tor (SOCKS5 :9050) - alias que usa SOCKS5 con puerto 9050 por defecto
- I2P (SOCKS5 :4444) - alias que usa SOCKS5 con puerto 4444 por defecto
Host proxy: IP o hostname del proxy (ej.
127.0.0.1)Puerto proxy: Puerto del proxy (Tor: 9050, I2P: 4444, SOCKS generico: 1080)
Usuario (opcional): dejar vacío si el proxy no requiere autenticación
Contraseña (opcional): dejar vacío si el proxy no requiere autenticación
Proxy por-servidor (legado)
Cada servidor upstream puede tener su propio campo SOCKS5 Proxy (opc) en formato host:puerto. Si un servidor tiene este campo configurado, usa ese proxy en lugar del global. Si esta vacío, usa el Proxy Universal si esta activo.
127.0.0.1:9050 - Tor Daemon127.0.0.1:4444 - I2Pproxy.example.com:1080 - Proxy SOCKS5 externoEste metodo solo soporta SOCKS5 sin autenticación. Para autenticación o SOCKS4 usar el Proxy Universal.
Prioridad
Servidor sin proxy por-servidor + Proxy Universal activo → usa el Proxy Universal
Servidor sin proxy por-servidor + Proxy Universal inactivo → conexión directa
Uso con Tor
1. Instalar Tor: apt install tor / en Windows, Tor Browser o Tor Expert Bundle
2. Tor escucha en 127.0.0.1:9050 por defecto
3. En Config → Proxy Universal: selecciónar Tor (SOCKS5 :9050), host 127.0.0.1
4. La direccion del servidor upstream debe ser una direccion .onion o IP que Tor pueda resolver
Funcionamiento interno
- Candela conecta al proxy en la IP:puerto configurados
- Negocia el handshake SOCKS4 o SOCKS5 (con o sin autenticación segun configuración)
- El proxy establece la conexión TCP al servidor Candela destino
- Todo el trafico P2P (ChaCha20-Poly1305) fluye por el tunel desde ese momento
Consideraciones de latencia
- Tor añade tipicamente 100-300ms de latencia por hop. Puede afectar al tiempo de resolución ECM.
- I2P tiene latencia aun mayor. Recomendado solo para nodos con cache CW activo.
- SOCKS5 local o corporativo: latencia despreciable.
🔀 CAID Tunneling
El CAID Tunneling permite que Candela anuncie un CAID diferente al real cuando se conecta a un servidor upstream. Útil cuando el servidor upstream no tiene el CAID correcto pero tiene otro compatible.
Caso de uso típico
Escenario: Tienes una tarjeta Betacrypt (CAID 0x1722) pero el servidor upstream solo sirve Nagravision de cable (CAID 0x1834).
Solución: Configurar un túnel 0x1722 → 0x1834. Candela envíará las ECMs al upstream como si fueran del CAID 0x1834 y el servidor las resolverá.
Funciona porque los CAIDs 17xx de Betacrypt son técnicamente túneles sobre Nagravision - el algoritmo de descifrado es el mismo.
Configuración en config.json
"caid_tunnels": [
{ "from": "0x1702", "to": "0x1833" },
{ "from": "0x1722", "to": "0x1834" }
]En el WebIf → Config → sección "CAID Tunneling". Al añadir un túnel se muestra la nota: "Túnel activo - el lector anunciará ambos CAIDs en el Card Map".
Pares compatibles conocidos
| CAID origen | CAID destino | Motivo |
|---|---|---|
| 0x1702 (Betacrypt) | 0x1833 (Nagra) | Betacrypt = Nagra con CAID distinto (Sky Deutschland) |
| 0x1722 (Betacrypt) | 0x1834 (Nagra) | Betacrypt = Nagra con CAID distinto (Kabel Deutschland) |
| 0x0500 (Viaccess) | 0x0500 | Mismo CAS, diferente ProvID (vía services filter) |
Implementación
Al procesar una ECM, el motor interno comprueba si el CAID solicitado tiene un túnel configurado antes de enrutar la petición.
🔌 NewCamd / MGcamd: Compatibilidad con NCam/OSCam
A partir de R40, Candela es compatible con los protocolos NewCamd y MGcamd, los mismos que usan NCam y OSCam. Esto permite íntegrarlo en instalaciones existentes sin reemplazar toda la infraestructura.
Diferencias entre protocolos
| Característica | NewCamd | MGcamd |
|---|---|---|
| Puerto | Un puerto por CAID | Un solo puerto para todos los CAIDs |
| Anuncio de tarjetas | MSG_CARD_DATA: un CAID/ProvID | MSG_CARD_DATA: lista de N pares CAID:ProvID |
| Autenticación | DES/3DES con deskey de 14 bytes + MD5 password | Idéntica a NewCamd |
| Caso de uso | Integración con NCam/OSCam por CAID individual | Servidor multi-CAID único (menos puertos) |
Autenticación y cifrado (común a ambos)
El handshake sigue el estándar NewCamd:
- Servidor envía 14 bytes aleatorios (rand14).
- Clave de sesión:
session_key[i] = rand14[i] XOR deskey[i] - 3DES-EDE2-CBC:
key1 = session_key[0..7],key2 = session_key[6..13](solape de 2 bytes, compatible OSCam). - IV = 16 bytes cero.
- Login: cliente envía
MSG_LOGINcon usuario + MD5(password). Servidor respondeMSG_LOGIN_ACKoMSG_LOGIN_NAK.
candela_mode=1) para añadir ChaCha20 sobre DES/3DES - ver sección más abajo.Modo servidor: Candela sirve tarjetas
Candela abre un puerto NewCamd o MGcamd para que NCam/OSCam se conecten como clientes y pidan descifrado de ECMs. Útil cuando NCam/OSCam ya está instalado en el mismo equipo o en la red local y se quiere añadir Candela como fuente de CWs.
Configuración (WebIF - Clientes - Protocolo: NewCamd o MGcamd):
| Campo | Descripción |
|---|---|
| Puerto | Puerto TCP que Candela escucha. En NewCamd: uno por CAID. En MGcamd: uno para todos. |
| Usuario / Contraseña | Credenciales que debe usar el cliente NCam/OSCam. |
| DES Key | 14 bytes en hex (0102030405060708090A0B0C0D0E). Debe coincidir en cliente y servidor. |
| CAID / ProvID | Solo NewCamd: CAID y ProvID que anuncia este puerto. |
IPs permitidas (allowed) | Lista de IPs/rangos separados por coma que pueden conectarse. Formatos: IP exacta, CIDR (192.168.0.0/24), comodín (192.168.*). Vacío = cualquier IP. |
Máx. clientes (max_clients) | Límite de conexiónes TCP simultáneas. 0 = límite compilado (64). |
Keepalive (keepalive_enabled) | 1 = mantiene la conexión con pings periódicos (recomendado). 0 = cierra por inactividad. |
Modo Candela (candela_mode) | 1 = activa capa ChaCha20 anti-DPI adicional. Solo funcióna si el cliente también es un nodo Candela con candela_mode=1. Con NCam/OSCam cae en modo legado automáticamente. |
| Activo | Activa/desactiva este servidor sin borrar la configuración. |
En NCam/OSCam configurar una N-line (NewCamd) o M-line (MGcamd) apuntando a la IP de Candela con los mismos parámetros.
Modo cliente: Candela consume tarjetas de NCam/OSCam
Candela se conecta a un NCam/OSCam existente y usa sus tarjetas para resolver ECMs. Las tarjetas recibidas por esta vía aparecen en el Card Map como hop=0, is_hw=1, igual que una tarjeta física local.
Configuración (WebIF - Servidores - Protocolo: NewCamd o MGcamd):
| Campo | Descripción |
|---|---|
| IP / Host | Dirección del NCam/OSCam al que conectar. |
| Puerto | Puerto del servidor NewCamd/MGcamd en el NCam/OSCam. |
| Usuario / Contraseña | Credenciales configuradas en NCam/OSCam. |
| DES Key | 14 bytes en hex. Debe coincidir con el servidor. |
| CAID / ProvID | Solo NewCamd: CAID/ProvID que sirve este reader. En MGcamd se obtiene automáticamente del MSG_CARD_DATA. |
| Etiqueta | Nombre descriptivo para el Card Map (p.ej. NCam-local). |
Modo Candela (candela_mode) | 1 = activa capa ChaCha20 al conectar. Si el servidor remoto no es Candela, cae en modo legado automáticamente. |
Apariencia en el Card Map
Las tarjetas recibidas por NewCamd/MGcamd aparecen como:
CAID:ProvID hop=0 hw=1 via=newcamd (etiqueta)El campo hop=0 indica tarjeta de primer nivel (sin reshare). El campo hw=1 indica que el sistema la considera hardware físico a efectos de enrutamiento de ECMs.
Filtros, cuentas y rate-limiting
En modo servidor, cada cliente NCam/OSCam se identifica por el usuario autenticado en el handshake (no un usuario genérico interno). Esto significa:
- El rate-limiter de ECMs (
ecm_ratelimit) se aplica por usuario individual. - Los filtros globales de CAID/Ident/SRVID se aplican a todas las ECMs entrantes.
- Si existe en la config una cuenta Candela con el mismo nombre de usuario, se aplican sus restricciones de
servicesymax_hops. - La caché CW es compartida: si la ECM ya fue resuelta por otro cliente (Candela o NCam/OSCam), se sirve desde caché sin tocar el lector.
- SCC, ETS, MCRR y Coalescing se aplican igualmente sobre los lectores físicos que sirven la respuesta.
Flujo ECM en modo cliente
- Llega una ECM para CAID X (tabla even 0x80 u odd 0x81).
- El motor comprueba caché, lectores locales y SCC/MCRR antes de llegar al reader NewCamd/MGcamd.
- Si hay reader conectado para ese CAID, envía el
MSG_ECMy esperaMSG_CW_OK. - La CW obtenida se guarda en caché ("NewCamd" / "MGcamd" como fuente) para peticiónes posteriores.
- Si responde
MSG_ECM_NAK, el motor escala a la red P2P Candela.
Modo Candela - Capa ChaCha20 anti-DPI (R40)
El Modo Candela añade una segunda capa de cifrado ChaCha20 sobre DES/3DES cuando ambos extremos son nodos Candela con candela_mode=1. Con NCam/OSCam el protocolo cae en modo legado sin ningúna interrupción.
Negociación CNDL
- Cliente Candela (con
candela_mode=1) añade al payload de login:CNDL[4] + NodeID[8 bytes binario](12 bytes extra al final). - Servidores NCam/OSCam ignoran estos bytes extra: el protocolo NewCamd solo parsea
usuario\0 md5[16], el resto es inerte. - Si el servidor Candela detecta el magic
CNDLy tienecandela_mode=1, responde en el ACK conCNDL + NodeIDdel servidor. - Si el ACK no contiene
CNDL, el cliente desactiva el Modo Candela y continúa en modo legado estándar.
Derivación de clave ChaCha20
ckey32 = SHA-256(session_key14 || "CANDELA_LAYER_V1")La derivación usa los 14 bytes de session key DES (ya negociados en el handshake estándar). No hay intercambio adicional de clave: ambos extremos calculan el mismo resultado de forma independiente.
Aplicación de la capa
Tras el handshake, todos los mensajes con payload (CARD_DATA, ECM, CW) se procesan con doble capa:
- Envío: ChaCha20 (capa Candela) sobre el payload en claro, después DES/3DES (capa NewCamd).
- Recepción: se deshace DES/3DES primero, después ChaCha20.
Los contadores ChaCha20 son independientes por dirección (cm_send_ctr / cm_recv_ctr, uint32). Solo se incrementan con payload de longitud mayor que cero: los mensajes sin datos (keepalive, etc.) no consumen contador, garantizando sincronismo de ambos extremos sin intercambio de estado.
Lo que el Modo Candela consigue y lo que no
| Aspecto | Modo legado (DES/3DES solo) | Modo Candela (ChaCha20 + DES/3DES) |
|---|---|---|
| Contenido de ECMs/CWs legible sin clave | Con hardware DES dedicado | No (ChaCha20 opacifica el contenido) |
| Firma del protocolo NewCamd detectable por DPI | Sí | Sí - el handshake y las cabeceras siguen siendo estándar NewCamd |
| Perfect Forward Secrecy (PFS) | No | No - la clave deriva de la session key DES |
| Compatibilidad con NCam/OSCam | Sí | Sí - cae en modo legado automáticamente |
| Protección ante correlación temporal de tráfico | No | No - los tiempos y tamaños de paquete son idénticos |
Configuración en config.json
"newcamd_readers": [
{ "label":"NCam-local", "host":"127.0.0.1", "port":15000, "user":"user1", "pass":"pass1", "deskey":"0102030405060708090A0B0C0D0E", "caid":"0500", "provid":"000000", "candela_mode":0, "enabled":1 }
],
"newcamd_servers": [
{ "port":15001, "caid":"0500", "provid":"000000", "user":"user1", "pass":"pass1", "deskey":"0102030405060708090A0B0C0D0E", "allowed":"", "max_clients":0, "keepalive_enabled":1, "candela_mode":0, "enabled":1 }
],
"mgcamd_readers": [
{ "label":"OSCam-mg", "host":"192.168.1.10", "port":16000, "user":"mg1", "pass":"mg1pass", "deskey":"0102030405060708090A0B0C0D0E", "candela_mode":0, "enabled":1 }
],
"mgcamd_servers": [
{ "port":16001, "user":"mg1", "pass":"mg1pass", "deskey":"0102030405060708090A0B0C0D0E", "allowed":"", "max_clients":0, "keepalive_enabled":1, "candela_mode":0, "enabled":1 }
]Mejoras de calidad en servidores NewCamd/MGcamd (R41)
ECM Coalescing
Cuando varios clientes conectados al servidor NewCamd o MGcamd solicitan el mismo ECM simultáneamente (mismo CAID, SRVID y hash de payload), Candela lanza una sola resolución al lector y hace esperar al resto en un pthread_cond_t. Cuando la CW llega, todos los clientes en espera la reciben al instante.
- Pool de 128 slots compartido entre servidores NewCamd y MGcamd.
- El primer cliente que llega al slot activa la resolución; los demás esperan sin contención.
- Si el pool está lleno, el cliente resuelve directamente sin coalescing (degradación suave).
Detección y purga de CW mala
Si un cliente reenvía el mismo ECM (mismo hash MD5 del payload) en menos de 5 segundos, Candela interpreta que la CW anterior era inválida y actúa:
- Elimina la CW mala de la caché de forma selectiva (
cache_invalidate_ecm()). - Fuerza una nueva resolución al lector en lugar de devolver la CW cacheada.
disablecrccws y disablecrccws_only_for). El mecanismo detecta el reenvío del mismo ECM como señal de que el STB no pudo descifrar la imagen, sin anular ningún parámetro de configuración del usuario.Push proactivo de CW
Cuando la caché recibe una CW nueva (por cualquier fuente: lector local, P2P, reader NC/MG), los clientes NewCamd/MGcamd que estén esperando una CW para ese mismo servicio son notificados inmediatamente a través de un pipe(2) interno por cliente. El thread de cada cliente monitoriza el pipe en su select() principal.
- La notificación transporta CAID, SRVID y la CW (23 bytes).
- El dispatch filtra por hash del ECM del cliente: solo despierta el coal slot del cliente si corresponde al mismo ECM que está esperando. Esto evita entregar una CW de un período de cifrado diferente (odd vs. even).
- Si la CW no pasa el filtro de validez (
cw_is_valid()), se descarta.
Métricas de calidad por cliente
El JSON de la API de clientes conectados (/api/peers/list) incluye para cada cliente NewCamd/MGcamd:
| Campo | Descripción |
|---|---|
latency | Tiempo de resolución del último ECM en milisegundos (medido con CLOCK_MONOTONIC). |
last_ecm_ms | Mismo valor que latency (campo explícito para compatibilidad). |
last_ecm_at | Timestamp Unix del último ECM procesado. |
consecutive_fails | Número de NAKs consecutivos sin CW válida entre medias. Se resetea a 0 al recibir una CW_OK. |
El WebIF muestra estos valores en la tabla de clientes conectados (escritorio y móvil): la latencia como tooltip en el badge de protocolo y los fallos consecutivos como badge rojo.
Validación por consenso en Modo Candela
Cuando Modo Candela está activo (candela_mode=1) y hay al menos 2 peers P2P Candela conectados, la CW obtenida no se envía inmediatamente al cliente. Candela espera hasta 800 ms a que la red P2P confirme la misma CW para ese servicio. Si la red devuelve una CW diferente, se descarta la CW local y se responde con NAK.
🔑 Nagravision / CAK7 / Merlin
Parámetros de tarjeta Nagra
| Parámetro | Obligatorio | Descripción |
|---|---|---|
| RSA Key | Sí (con tarjeta local) | Módulo RSA de la tarjeta. Necesario para descifrar EMMs personalizadas (únicas por tarjeta). Sin RSA Key, la tarjeta no puede actualizarse. |
| BoxKey | Sí (con tarjeta local) | Clave del receptor asociada a la tarjeta. Junto con la RSA Key establece la sesión de descifrado de EMMs. |
| BoxID | Opcional | Identificador del receptor. Algunos providers Nagra 3 modernos lo solicitan de forma adicional. Diferente del BoxID NDS. |
| NUID | Opcional | NUID de la tarjeta. Requerido en algunos providers CAK7/Merlin modernos. |
| CWEKey | Opcional | CW Encryption Key. Requerida en Nagra 3 CAK7/Merlin cuando el provider usa CWE (Control Words Encriptadas). Sin CWEKey estos canales no se abren. |
CAK7 / Nagra Merlin
CAK7 es el protocolo de seguridad mejorado de las tarjetas Nagra Merlin modernas. A diferencia de Nagra2 estándar (solo RSA), CAK7 añade una segunda capa de cifrado AES-128-ECB sobre la CW resultante del RSA.
Flujo de descifrado CAK7
ECM → RSA decrypt (BN_mod_exp, clave RSA 64 bytes)
→ CW cifrada (16 bytes)
→ AES-128-ECB decrypt con CWEKey
→ CW real (16 bytes) → DVBAPI → descrambler ✓
Providers CAK7 conocidos
| Operador | CAID | Requiere CWEKey |
|---|---|---|
| Canal+ France / TNT Sat | 0x1811, 0x1812 | Sí |
| Canal+ PL / NC+ | 0x1813, 0x1884 | Sí |
| Tivùsat (Italia) | 0x1856 | Sí (Tarjetas negras/verdes) |
| Cyfrowy Polsat (Polonia) | 0x1861, 0x186C | Sí |
| HD+ (Alemania) | 0x186A, 0x186D | Sí (Tarjetas HD03 en adelante) |
Candela detecta automáticamente si el CAID del lector es CAK7 y aplica el descifrado CWEKey si está configurada. Sin CWEKey en providers que la requieren, la CW llega cifrada y el canal no abre.
Herramienta Nagra Key Calculator (Forense)
Dado el RSAKey y el BoxKey, calcula los parámetros derivados: NUID, ECMKey, CWEKey y BoxKey extendida. Los cálculos usan operaciónes XOR estándar de Nagra 2/3 - son heurísticos y funciónan para la mayoría de providers, pero algunos pueden tener variaciones propietarias.
🔌 Referencia API REST
Todos los endpoints requieren autenticación HTTP Basic (usuario:contraseña configurados en http_user / http_pwd). Las peticiónes POST esperan Content-Type: application/json. WebIF soporta TLS 1.3, failban íntegrado (10 intentos → bloqueo 1 hora) y rate limiting por IP.
Estado y monitoreo
| Método | Endpoint | Descripción |
|---|---|---|
| GET | /api/status | Estado global: uptime, RAM, peers activos, TLS activo, versión. |
| GET | /api/perf | Métricas de rendimiento: CPU, RAM, latencia media ECM. |
| GET | /api/stats/sessions | Sesiones activas por usuario con duración e historial. |
| GET | /api/stats/cache | Estadísticas caché CW: hits, misses, slots usados, tasa de acierto. |
| GET | /api/top_services | Servicios/canales más solicitados por número de ECMs. |
| GET | /api/status/cws | CWs activas en vivo desde DVB-API con contadores de CWs envenenadas (CWS). |
| GET | /api/demux | Estado de demuxes DVB-API activos con CAID, SRVID y latencias. |
| GET | /api/monitor/cw_cycles | CWP: ciclos CW predichos por canal (EWMA), muestras y estado de prefetch. |
ECM y CW
| Método | Endpoint | Descripción |
|---|---|---|
| GET | /api/ecm/history | Historial de ECMs procesadas recientemente con CAID, SRVID, latencia y fuente. |
| GET | /api/ecm/log | Últimas N entradas del log ECM. |
| POST | /api/cw/inject | Inyectar CW constante por canal (debug/testing). |
Configuración dinámica
| Método | Endpoint | Descripción |
|---|---|---|
| GET | /api/config | Configuración completa en JSON. |
| POST | /api/config | Guardar configuración completa. |
| POST | /api/config/global | Actualizar parámetros globales (port, nodeid, etc.) sin tocar accounts/servers. |
| POST | /api/config/csa | Actualizar parámetros CSA/DVBAPI en caliente. |
| POST | /api/config/accounts | Añadir/editar cuenta de cliente. |
| DELETE | /api/config/accounts?user=X | Eliminar cuenta de cliente. |
| POST | /api/config/servers | Añadir servidor upstream. |
| DELETE | /api/config/servers?ip=X&port=Y | Eliminar servidor upstream. |
| POST | /api/config/auth | Cambiar credenciales de acceso al WebIF. |
| POST | /api/config/tls_generate | Generar certificado TLS auto-firmado para el WebIF. |
| GET | /api/config/backup | Descargar ZIP con todos los archivos de configuración. |
| POST | /api/config/restore | Restaurar configuración desde ZIP de backup. |
| POST | /api/toggle_state | Pausar/reanudar nodos P2P en RAM al instante sin reiniciar. |
Archivos de configuración
| Método | Endpoint | Descripción |
|---|---|---|
| GET | /api/files/services | Contenido de candela.services. |
| POST | /api/files/services | Guardar candela.services. |
| GET | /api/files/srvid | Contenido de candela.srvid. |
| POST | /api/files/srvid | Guardar candela.srvid. |
| GET | /api/files/provid | Tabla de PROVIDs (nombre/descripción por PROVID). |
| GET | /api/files/fakecws | Contenido de la blacklist FakeCW. |
| POST | /api/files/fakecws | Guardar blacklist FakeCW. |
| GET | /api/softcam/keys | Lista de claves SoftCam cargadas en memoria. |
| GET | /api/softcam/file | Contenido raw del archivo SoftCam.Key. |
| POST | /api/softcam/save | Guardar SoftCam.Key en disco. |
| POST | /api/softcam/reload | Recargar SoftCam.Key en caliente sin reiniciar. |
Peers y red P2P
| Método | Endpoint | Descripción |
|---|---|---|
| GET | /api/peers | Lista de peers conectados con NRS, latencia y estado. |
| GET | /api/peers/discovered | Peers descubiertos automáticamente (PIR + NETMAP). |
| GET | /api/peers/lan | Peers descubiertos en la LAN via beacon UDP (LAN Discovery). |
| GET | /api/peers/netmap | NETMAP: mapa topológico - IP, puerto, hops, proto_ver, nombre, país, NRS score, last_seen. |
| GET | /api/peers/nrs | NRS: puntuaciones por servidor - score, latencia media, connects OK/fail, ECMs entregados. |
| GET | /api/peer/cardmap?ip=X | Card Map anunciado por un peer específico. |
| GET | /api/nodes | Node Gossip: operadores anunciados en la red (nombre, país, proto_ver). |
| GET | /api/services/list | Lista de servicios configurados para el WebIF. |
| GET | /api/entitlements?reader=X | Entitlements (suscripciones activas) de una tarjeta local. |
| GET | /api/cas/name?caid=X | Nombre del CAS asociado a un CAID hexadecimal. |
Seguridad y control de acceso
| Método | Endpoint | Descripción |
|---|---|---|
| GET | /api/security/events | Eventos de seguridad recientes con clasificación de severidad. |
| GET | /api/security/events/count | Contador de eventos de seguridad sin leer. |
| POST | /api/security/events/clear | Vaciar el log de eventos de seguridad. |
| POST | /api/security/events/delete | Eliminar un evento de seguridad individual. |
| POST | /api/security/events/read | Marcar evento como leído. |
| GET | /api/security/jail | IPs en ban temporal o permanente (failban + permaban). |
| POST | /api/security/jail/pardon | Desbloquear IP baneada. |
| GET | /api/security/alerts | Estado de umbrales de alerta y si están siendo superados. |
| GET | /api/security/watchlist | PIR: IPs marcadas por peers (watchlist local) con IP, tipo, severidad y TTL. |
| GET | /api/security/pir | PIR: estadísticas - eventos envíados/recibidos/rate-limited, tamaño watchlist. |
| GET | /api/security/advanced | Configuración de seguridad avanzada P2P (p2p_allowed, max_conn_ip, etc.). |
| POST | /api/security/advanced | Actualizar configuración de seguridad avanzada. Aplica en caliente. |
| POST | /api/security/block | Bloqueo manual de IP. |
| POST | /api/security/unblock | Desbloqueo manual de IP. |
| POST | /api/security/unblock_all | Desbloquear todas las IPs bloqueadas de una sola operación. |
| POST | /api/security/whitelist | Añadir IP a la lista blanca (nunca bloqueada). |
| POST | /api/security/whitelist/remove | Remover IP de la lista blanca. |
| POST | /api/peer/permaban | Banear permanentemente un peer por IP. |
| POST | /api/peer/tempban | Banear temporalmente un peer (body: {"ip":"x","minutes":N}). |
| POST | /api/forensics/fakecw_add | Añadir CW a la blacklist de FakeCWs. |
Mensajería P2P (R31)
| Método | Endpoint | Descripción |
|---|---|---|
| GET | /api/messages | Mensajes P2P recibidos pendientes de leer. |
| POST | /api/messages/send | Enviar mensaje privado a peer (body: {"peer_ip":"x","msg":"texto"}). |
| POST | /api/messages/read | Marcar mensaje como leído. |
| POST | /api/messages/delete_one | Eliminar un mensaje individual del buzón. |
| DELETE | /api/messages/clear | Vaciar el buzón completo o el chat con un peer. |
Módulos forenses R33+ (ETO / CWS / ERD / CFI / EFG / CWRID / EEA / ECLD)
| Método | Endpoint | Descripción |
|---|---|---|
| GET | /api/forensics/timing | ETO: perfiles de latencia ECM por peer+CAID - media, σ, histograma 16 cubos, anomalías. |
| GET | /api/forensics/replay | ERD: Replay Detector - cache hits, hits retardados, retardo total/último/CAID. |
| GET | /api/forensics/cfi | CFI: Fingerprint Inversion - hits, delayed, passthrough, retardo total/último/CAID. |
| GET | /api/forensics/cascade | EFG: configuración activa del Flow Guard - max_sids, min_ecms, window_sec, penalty_sec. |
| GET | /api/forensics/cwrid | CWRID: stats (cw_checked, replay, lateral) + eventos recientes con hash SHA256[:8], CAID, SRVID. |
| GET | /api/forensics/entropy | EEA: perfiles por CAID - muestras, alertas, entropía media/mín/máx/última. Umbral: 7.0 bits/byte. |
| GET | /api/forensics/chain | ECLD: ring buffer de últimas 64 cadenas ECM con desglose T0–T4 + estadísticas globales. |
| GET | /api/forensics/cw | CWs activas y recientes con CAID, SRVID, latencia y peer origen. |
| GET | /api/forensics/emm | EMMs capturadas en el EMM Vault con tipo, CAID y timestamp. |
| GET | /api/forensics/apdu | Historial de APDUs envíados/recibidos a lector local con respuesta ISO-7816. |
| POST | /api/forensics/apdu_send | Enviar APDU ISO-7816 arbitrario directo a un lector local y obtener respuesta. |
| POST | /api/forensics/nagra_calc | Calculadora Nagravision: NUID/ECMKey/CWEKey/BoxKeyExt desde RSAKey+BoxKey. |
| POST | /api/forensics/ecm_sim | Inyectar ECM sintética al motor de procesamiento (ECM Simulator / Fuzzer). |
Softcam Virtual MOSC
| Método | Endpoint | Descripción |
|---|---|---|
| GET | /api/forensics/mosc_list | Lista de clones de tarjeta en RAM (hasta 8 simultáneos). |
| GET | /api/forensics/mosc_state | Estado del clone activo: UA, tiers, fechas, claves cargadas. |
| POST | /api/forensics/mosc_clone | Crear nuevo clone desde lector físico - copia UA, tiers, ATR y claves CAS. |
| POST | /api/forensics/mosc_activate | Activar/desactivar un clone como lector virtual en el pool. |
| POST | /api/forensics/mosc_select | Cambiar el clone activo para operaciónes forenses. |
| POST | /api/forensics/mosc_edit | Editar campos del clone (tiers, fechas de expiración, claves CAS). |
| POST | /api/forensics/mosc_edit_field | Editar campo individual del clone sin tocar el resto. |
| POST | /api/forensics/mosc_emm | Inyectar EMM al clone para simular actualización de tarjeta. |
| DELETE | /api/forensics/mosc_delete | Eliminar un clone de la RAM. |
| POST | /api/forensics/virtual_mosc | Calcular hash MOSC para una CW concreta. |
Auditoría y logs
| Método | Endpoint | Descripción |
|---|---|---|
| GET | /api/log | Últimas líneas del log en vivo. |
| GET | /api/audit/log | Ring buffer del audit log cifrado: conexiónes, auth fallidas, bans, cambios de config. |
Mantenimiento
| Método | Endpoint | Descripción |
|---|---|---|
| POST | /api/cache/flush | Limpiar caché CW completamente. |
| POST | /api/cache/stats | Estadísticas detalladas de caché CW en tiempo real. |
| POST | /api/reader/restart | Reiniciar lector de tarjeta local. |
| POST | /api/server/reconnect | Forzar reconexión inmediata a un servidor upstream específico. |
| POST | /api/system/restart | Reiniciar el proceso Candela. |
| GET | /api/borraoff | Estado de nodos offline con nivel de penalización (AVISO/PENALIZADO/BLOQUEADO). |
| POST | /api/borraoff/reset | Resetear penalización BorraOff pendiente para un nodo. |
🏷 Codenames de versión
A partir de R35, cada versión lleva un codename: una sola palabra en español, de temática defensiva o de infraestructura, que identifica la versión en logs y comunicaciónes. Aparece en el arranque como Candela Softcam v1.0 (R42 - Cóndor).
Versiones
| Versión | Codename | Por qué |
|---|---|---|
| R35 | Atalaya | Cierre del perímetro de seguridad: EFG (Flow Guard), FakeCW, DoubleCheck, reshare enforcement con flag de protocolo, failban CGNAT, ECDH Rekey sin corte TCP. Una atalaya es una torre de vigilancia que observa el horizonte y avisa del peligro antes de que llegue. |
| R36 | Vigía | Inteligencia colectiva y análisis forense avanzado: PIR (Peer Intelligence Ring - compartir baneos entre nodos), CFI (CAS Fingerprint Inversion - retardo mínimo plausible por CAID), audit log cifrado, alertas por umbral, CW Cycle Check avanzado por CAID, Double Check selectivo por CAID, caché CW/ECM con límites de memoria configurables. El vigía es quien observa sin descanso y alerta al colectivo. |
| R37 | Alcázar | Arquitectura de red P2P inexpugnable: NETMAP gossip (descubrimiento automático de topología completa), NSS (Node Status Signal - apagado limpio sin pantalla negra), NRS (Node Reputation Score - scoring de upstreams), Anti-Eclipse (diversidad de subred), LAN Discovery (detección UDP de instancias locales), AMPE (Adaptive Multi-Path ECM - consulta paralela de peers para latencia mínima). Un alcázar es la fortaleza que lo defiende todo desde el interior. |
| R38 | Bastión | Sigilo ante la operadora: SCC (Simultaneous Channel Cap - limita los canales simultáneos visibles en la CA) y ETS (ECM Temporal Spreading - distribuye en el tiempo las ECMs de canales nuevos en ráfaga). Junto con TAR (R37), cubre todos los vectores detectables tanto a nivel de ISP como de sistema CA. Un bastión es el elemento más avanzado de la fortaleza, el que protege el punto más expuesto. |
| R39 | Fortaleza | Cierre del ciclo TAR y eficiencia de hardware: Proxy Universal (enrutamiento P2P por SOCKS5/HTTP CONNECT), GSP (Gossip Shuffle Privacy - Fisher-Yates parcial en gossip para romper el orden determinista de propagación), ECM Relay (ruptura de correlación IP ante observadores externos por CMD 0x17/0x18), MCRR (Multi-Card Round-Robin - distribución de carga entre lectores físicos por SRVID). Una fortaleza es la suma de todos sus elementos defensivos íntegrados. |
| R40 | Pasarela | Interoperabilidad con el ecosistema NCam/OSCam: soporte bidireccional de protocolos NewCamd y MGcamd. Candela puede actuar como servidor o cliente de ambos protocolos. Las tarjetas de terceros se íntegran en el Card Map como hop=0/is_hw=1. Una pasarela conecta dos mundos distintos sin comprometer la seguridad de ningúno. |
| R41 | Centinela | Calidad y seguridad en la entrega de CWs NewCamd/MGcamd: coalescing de ECMs duplicadas, detección y purga automática de CWs malas, push proactivo de CW por pipe, métricas de calidad por cliente y válidación por consenso P2P en Modo Candela. Un centinela observa, detecta y actúa antes de que el problema llegue al usuario. |
| R42 | Cóndor | Rendimiento y compatibilidad de build: LZ4 reemplaza LZO en assets WebIF, zlib nivel 1 para primera carga ultrarápida, corrección del bug de configuración en Windows (fopen binario), compatibilidad GCC 4.5 (pragma fuera de función), regla Makefile lz4 correcta y detección de punteros LFS en build_libs. El cóndor vuela alto, ligero y sin rozadura. |
📄 Campos config.json
| Campo | Default | Descripción |
|---|---|---|
| candela_port | 15000 | Puerto TCP del servidor P2P. |
| web_port | 8080 | Puerto del WebIf. |
| nodeid | auto | Identificador único del nodo (64 bits hex). Generado aleatoriamente en el primer arranque. |
| pidfile | auto | Ruta al fichero PID para detección de doble arranque. auto = <dir_config>/candela.pid. "none" = desactivado. Permite correr varias instancias con distintos -c. |
| silent_mode | 0 | 0=normal, 1=sin output en consola. |
| enable_forensics | 1 | Activa la pestaña Forense ACF y el módulo de captura EMM. |
| ghost_ua | "" | Bytes hex del Ghost UA para anti-fingerprinting. |
| http_allowed | 127.0.0.1,192.168.0.0/16 | IPs permitidas para el WebIf. |
| tls_cert_file | "" | Ruta al certificado TLS. Vacío = HTTP. |
| tls_key_file | "" | Ruta a la clave privada TLS. |
| enable_softcam | 1 | Activa el emulador SoftCam. |
| enable_dvbapi | 1 | Activa la interfaz DVBAPI. |
| enable_streamrelay | 1 | Activa el motor StreamRelay CSA SIMD. Requiere enable_dvbapi=1. |
| pmt_mode | 0 | 0=estándar, 1=rápido. |
| cw_cycle_check | 1 | CW Cycle Check (anti-freeze). |
| enable_doublecheck | 0 | DoubleCheck por consenso de peers. |
| disablecrccws | 0 | Desactivar CRC check global. |
| disablecrccws_only_for | "" | CAIDs separados por coma para desactivar CRC selectivamente. |
| preferlocalcards | 1 | Priorizar tarjetas locales (Hop 0). |
| cw_cache_size | 2048 | Slots máximos de caché CW en RAM. |
| ecm_ratelimit | 4 | ECMs/segundo máximo por cliente. |
| offline_cache_ttl | 30 | TTL de la caché cuando el upstream está caído (segundos). |
| client_timeout | 5000 | Timeout de espera de CW por peer (milisegundos). |
| enable_reshare | 1 | Redistribuir CWs recibidas a otros peers. |
| enable_ecmdb | 0 | ECM DB persistente en disco. |
| block_unknown_emm | 1 | Bloquear EMMs de tipo desconocido. |
| log_ecm | 0 | Log detallado de ECMs. |
| log_cw | 0 | Log detallado de CWs. |
| log_emm | 0 | Log de EMMs procesadas. |
| enable_cache_ecm | 1 | Caché ECM en RAM activa. |
| enable_cacheex | 0 | CacheEX - compartir caché con peers. |
| Red P2P - Identidad y Acceso (R32+) | ||
| p2p_allowed | "" | IPs/rangos permitidos como peers P2P. Vacío = sin restricción. Formato: "192.168.1.0/24,10.0.0.1". |
| p2p_max_conn_per_ip | 0 | Máximo conexiónes P2P simultáneas por IP. 0 = sin límite. |
| enable_audit_log | 0 | Activa audit log de eventos de seguridad en RAM. |
| enable_config_log | 0 | Loguea cada cambio de configuración con timestamp. |
| enable_p2p_chat | 0 | Activa mensajería privada P2P (R31). Requiere peers con R31+. |
| R33 - ETO / CWS / ERD / EFG | ||
| enable_eto | 1 | ECM Timing Oracle. Perfilado estadístico de latencia por peer+CAID. |
| cw_consensus_quorum | 2 | CW Consensus Shield. Número de peers que deben concordar en la misma CW. |
| enable_erd | 1 | ECM Replay Detector. Retardo sintético en cache hits para anti-fingerprinting. |
| erd_default_ms | 300 | Retardo base ERD en ms cuando ETO no tiene datos para la CAID. |
| erd_jitter_pct | 20 | Jitter en % aplicado al retardo ERD. Ej: 20 = ±20% del retardo medio. |
| enable_cfi | 1 | CFI - CAS Fingerprint Inversion. Retardo mínimo plausible por CAID usando el floor histórico ETO. Sustituye a ERD cuando ambos están activos. |
| cfi_default_ms | 50 | Floor mínimo CFI en ms cuando ETO aún no tiene datos para la CAID. |
| cfi_jitter_pct | 15 | Jitter ±% sobre el floor CFI. Mantiene la variación natural sin exceder el mínimo histórico. |
| R36 - PIR: Inteligencia Colectiva | ||
| enable_pir | 1 | PIR - Peer Intelligence Ring. Compartir eventos de seguridad con peers autenticados. |
| pir_watchlist_ttl_h | 24 | TTL en horas de las IPs marcadas por peers en la watchlist local. |
| pir_rate_limit | 5 | Máximo de eventos de seguridad a compartir por minuto (anti-spam). |
| R37 - NETMAP / NSS / NRS / Anti-Eclipse | ||
| node_country | "" | País del nodo (ISO 3166-1 alpha-2, ej. ES). Se anuncia en NETMAP gossip. |
| enable_nss | 1 | NSS - Node Status Signal. Anuncia apagado a peers antes de cerrar (evita pantalla negra). |
| enable_nrs | 1 | NRS - Node Reputation Score. Ordena servidores upstream por calidad histórica. |
| max_peers_per_subnet | 2 | Anti-Eclipse. Máx. peers activos del mismo bloque /24. 0 = sin límite. |
| enable_efg | 1 | ECM Flow Guard. Anti-cascade con Strict Cache Mode dinámico por peer. |
| efg_max_sids | - | Máximo de SIDs activos por peer antes de activar Strict Cache Mode. |
| efg_min_ecms | 2 | Mínimo de ECMs para considerar un SID "activo" (filtra zapping legítimo). |
| efg_window_sec | - | Ventana temporal en segundos para la evaluación EFG. |
| efg_penalty_sec | - | Duración del Strict Cache Mode en segundos tras detección de cascading. |
| R33 - CWRID / EEA / ECLD / OLG / Adaptive Timeout | ||
| enable_cwrid | 1 | CW Replay & Injection Detector. Detecta reutilización de CW y lateral sharing. |
| cwrid_window_sec | 30 | Ventana temporal en segundos para el CWRID. Cubre un criptoperíodo completo. |
| enable_eea | 1 | ECM Entropy Analyzer. Alerta si la entropía Shannon de una CW cae por debajo de 7.0 bits/byte. |
| enable_ecld | 1 | ECM Chain Latency Decomposer. Registra timestamps T0–T4 por ECM para diagnóstico de latencia. |
| enable_overlap_guard | 1 | ECM Overlap Guard. Entrega la última CW válida del canal al demux en cache miss para evitar pantalla negra. |
| overlap_guard_max_age_ms | 10000 | Antigüedad máxima en ms de la CW de soporte OLG. Si la última CW es más antigua, no se entrega. |
| R34 - CTC: Candela Transport Camouflage | ||
| enable_tls_camouflage | 1 | Framing Fake TLS 1.3 Record Layer. Activo por defecto. La detección incoming es siempre activa (MSG_PEEK); este flag controla solo el handshake outgoing. |
| R35 - CPM/DPM/Backoff/Keepalive: Hardening de Producción | ||
| enable_pulse_masking | 1 | Inyecta chaff CMD_PADDING de 200-1400 bytes cada 2-3.5s por peer autenticado. Rompe la firma temporal del criptoperíodo DVB. |
| ctc_sni | auto | SNI del ClientHello sintético: auto (generado desde NodeID), "" (sin SNI), o hostname propio. |
| enable_dpm | 1 | Decoy Port Multiplexing: responde HTTP/200 nginx a escáneres que envíen verbos HTTP al puerto P2P. |
| R35+ - Anti-Scanner: Honeypot CAIDs + CAID Probe Detection | ||
| honeypot_caids | "" | CAIDs trampa en hex separados por coma (ej: FFF1,FFF2,DEAD). Cualquier peer que solicite un ECM con uno de estos CAIDs es baneado al instante. Vacío = desactivado. |
| probe_caid_threshold | 8 | CAIDs únicos distintos que un peer puede solicitar dentro de la ventana antes de ser detectado como scanner. 0 = desactivado. |
| probe_caid_window_secs | 60 | Duración en segundos de la ventana deslizante para la detección de probing de CAIDs. |
| R37 - AMPE: Adaptive Multi-Path ECM | ||
| ecm_multipath | 3 | AMPE - peers en paralelo por ECM. 0 = todos. 1 = uno (clasico). N = top-N por score HLS. Sin límite superior. La primera CW válida se entrega; todos los que responden actualizan su score. Compatible con CWS y ERD. |
| card_hop_limit | 0 | Hop máximo aceptado en CMD_CARD_MAP de peers P2P. 0 = sin límite (acepta hasta hop 10). N = descarta tarjetas con hop > N. Maximo configurable: 10. |
| NewCamd / MGcamd | ||
| newcamd_readers | [] | Array de lectores NewCamd (upstream). Cada entrada: label, host, port, user, pass, deskey, caid, provid, candela_mode, enabled. |
| newcamd_servers | [] | Array de servidores NewCamd (clientes que te conectan). Cada entrada: port, caid, provid, user, pass, deskey, allowed, max_clients, keepalive_enabled, candela_mode, enabled. |
| mgcamd_readers | [] | Array de lectores MGcamd (upstream). Cada entrada: label, host, port, user, pass, deskey, candela_mode, enabled. El CAID se obtiene automáticamente del servidor. |
| mgcamd_servers | [] | Array de servidores MGcamd (clientes que te conectan). Cada entrada: port, user, pass, deskey, allowed, max_clients, keepalive_enabled, candela_mode, enabled. Sirve todos los CAIDs disponibles. |
📐 Formatos CW (64/128 bits)
Una Control Word (CW) es la clave simétrica que un receptor DVB usa para descifrar el stream. Candela maneja dos formatos según el CAS y el modo de operación.
CW estándar DVB-CSA (64 bits)
Longitud: 8 bytes (64 bits)
Estructura: 4 bytes even key + 4 bytes odd key
Uso: DVB-CSA1 (el más común). Movistar+, Sky, TDT, mayoría de plataformas europeas.
Ejemplo: AA BB CC DD EE FF 00 11 (even=AABBCCDD, odd=EEFF0011)
DVB-CSA1 usa las dos mitades de la CW en ciclos alternos. El descrambler hardware del receptor aplica el algoritmo CSA con la CW del período vigente.
CW extendida (128 bits)
Longitud: 16 bytes (128 bits)
Estructura: 8 bytes even key + 8 bytes odd key
Uso: DVB-CSA3, AES-128 (CAID CAK7/Nagra3, algunos providers asiáticos)
Ejemplo: AA BB CC DD EE FF 00 11 22 33 44 55 66 77 88 99
En el protocolo Candela
| Campo | Valor | Descripción |
|---|---|---|
| CMD_CW_RESP payload | 8 o 16 bytes | Candela detecta el tamaño automáticamente según el CAS |
| CMD_CW_PUSH payload | 8 o 16 bytes | Ídem en push proactivo |
| DVBAPI response | Siempre 16 bytes | Relleno con 0x00 en la parte alta si la CW es de 64 bits |
| SoftCam.Key tipo F | 8 o 16 bytes hex | Soporta BISS y Constant CW de 128 bits |
| SoftCam.Key tipo P | 7 o más bytes hex | Claves exclusivas para sistema PowerVu (CAID 0x0E00) |
CAK7 - CW cifrada
En Nagra CAK7/Merlin, la CW que sale del RSA está cifrada con AES-128-ECB usando la CWEKey del lector. Candela descifra automáticamente si CWEKey está configurada:
CW_cifrada (16 bytes) = RSA_decrypt(ECM, RSAKey)
CW_real (16 bytes) = AES_128_ECB_decrypt(CW_cifrada, CWEKey)
→ CW_real → DVBAPI → descrambler ✓
Detección automática en Candela
El motor DVBAPI examina el campo CA_type del ECM y el CAID del demux para determinar si usar CSA1 (8 bytes) o CSA3/AES (16 bytes). El motor CSA seleccióna automáticamente el modo correcto. El usuario no necesita configurar nada adicional.
CW Fake / CW Corruptas
Candela mantiene una lista negra de CWs conocidas como falsas o corruptas (configurada en config/candela.fakecws). Si un upstream devuelve una CW que coincide con la lista, se descarta y se marca al peer con penalización HLS. Ver sección FakeCW / CW Audit.
🔑 PFS / ECDH X25519 (Perfect Forward Secrecy)
¿Qué es PFS?
Perfect Forward Secrecy garantiza que el descifrado de tráfico pasado capturado sea imposible aunque un atacante obtenga la clave maestra en el futuro. Cada sesión P2P negocia un secreto compartido único derivado de claves efímeras X25519 que se descartan al cerrar la sesión.
Flujo de handshake ECDH (R30)
Cliente genera par de claves efímero: priv_A, pub_A (X25519)
→ CMD_ECDH_INIT (0x10): envía pub_A al servidor
Servidor genera par efímero: priv_B, pub_B
→ CMD_ECDH_RESP (0x11): envía pub_B al cliente
Ambos calculan: shared_secret = X25519(priv, pub_remoto)
session_key = HKDF-SHA256(shared_secret, nonce_A || nonce_B)
→ CMD_ECDH_ACK (0x12): confirmación
A partir de aquí: ChaCha20-Poly1305 con session_key derivada ECDH
Comandos nuevos en R30
| CMD | Nombre | Payload |
|---|---|---|
0x10 | CMD_ECDH_INIT | 32 bytes clave pública X25519 del iniciador + nonce[16] |
0x11 | CMD_ECDH_RESP | 32 bytes clave pública X25519 del receptor + nonce[16] |
0x12 | CMD_ECDH_ACK | HMAC-SHA256 de confirmación (evita MITM) |
Compatibilidad
La negociación ECDH es opcional y retrocompatible. Si un peer no soporta R30, el handshake usa el método anterior (ChaCha20-Poly1305 con clave derivada de credenciales). Cuando ambos peers son R30+, ECDH se activa automáticamente.
💬 Mensajería Privada P2P
enable_p2p_chat=1 en ambos extremos.Funcionamiento
Los mensajes P2P se transmiten usando los nuevos comandos del protocolo Candela cifrados con la clave de sesión ChaCha20-Poly1305. Solo pueden intercambiar mensajes peers que ya tienen una sesión autenticada activa - no es un sistema de mensajería anónimo.
peer_list[] ni disponen de sesión ECDH Candela. El código de despacho de CMD_MSG_SEND exige explícitamente peer->ecdh_active=1 y peer->authenticated=1, condiciones que solo cumplen los peers Candela nativos.Comandos R31
| CMD | Nombre | Descripción |
|---|---|---|
0x20 | CMD_MSG_SEND | Mensaje cifrado. Payload: 2 bytes longitud + texto UTF-8 (max 1024 bytes). |
0x21 | CMD_MSG_ACK | Acuse de recibo. Confirma que el peer recibió el mensaje. |
API de mensajería
| Endpoint | Descripción |
|---|---|
GET /api/messages | Lista de mensajes recibidos pendientes. |
POST /api/messages/send | Enviar mensaje: {"peer_ip":"x.x.x.x","msg":"texto"}. |
DELETE /api/messages/clear | Vaciar buzón de entrada. |
Activación
En Mantenimiento → WebIF y Sistema → activar enable_p2p_chat. El toggle aparece en el panel de mensajería. Si el peer remoto no tiene R31 o no tiene el chat activado, los mensajes envíados se descartan silenciosamente (no hay error).
🛡 Red P2P - Seguridad y Tommy hashlin O(1)
Fix: corrupción de config vía /api/config
En versiones anteriores, el endpoint POST /api/config aceptaba escritura directa de campos de seguridad sensibles (p2p_allowed, max_conn_ip) mezclados con la config general. En R32 estos campos se han separado a /api/security/advanced con válidación estricta de tipos y rangos, eliminando el vector de corrupción accidental o maliciosa.
Filtro triple en accept loop P2P
El bucle de aceptación de conexiónes P2P ahora aplica tres filtros antes de pasar al handshake:
- IP whitelist/blacklist: verifica
p2p_allowedsi está configurado. - Límite por IP: cuenta conexiónes activas de esa IP y rechaza si supera
p2p_max_conn_per_ip. - Failban: comprueba si la IP está en la lista de bans (tempban o permaban).
Conexiones rechazadas generan un evento en el audit log si está activo.
Tommy hashlin O(1) para ECMs pendientes
Hasta R31, el pool de ECMs pendientes (pending_ecms[1024]) se buscaba con O(n) scans líneales. En R32 se reemplazaron 6 bucles de búsqueda por una tabla hash incremental tommy_hashlin indexada por el hash MD5 de la ECM:
| Operación | Antes (R31) | Después (R32) |
|---|---|---|
| Deduplicación al encolar ECM | O(1024) scan | O(1) tommy_hashlin_bucket() |
| Entrega de CW (bcst_* broadcast) | O(1024) scan | O(k) bucket walk (k = simulcrypt) |
| DoubleCheck slot lookup | O(1024) scan | O(k) bucket walk |
| Estimación de latencia | O(1024) scan | O(k) bucket walk |
| hay_ecms_activas (watchdog) | O(1024) scan | O(1) tommy_hashlin_count() |
| Timeout watchdog | O(1024) scan | O(1024) solo si hay activas |
Con 1024 ECMs pendientes simultáneas (escenario extremo de carga), el ahorro por ciclo de watchdog es de ~6×1024 comparaciones eliminadas. En operación normal (pocas ECMs activas), el beneficio es aún mayor proporccionalmente.
Audit log y alertas
Sistema de audit log en RAM con ring buffer. Cuando enable_audit_log=1, todos los eventos de seguridad (conexiónes, autenticaciónes fallidas, bans, cambios de config) se registran con timestamp, IP y detalle. Consultable vía /api/audit/log.
Las alertas por umbral generan entradas automáticas: si un peer supera N ECMs/s, N FakeCWs/s o N intentos de auth fallidos, se genera una entrada ALERT en el log y el peer queda bajo vigilancia.
⏱ ETO - ECM Timing Oracle
GET /api/forensics/timing.El ETO registra la latencia de respuesta de cada ECM agrupada por fuente (IP del peer o etiqueta del lector) y CAID, construyendo un perfil estadístico en tiempo real que se usa como señal de seguridad para detectar upstreams degradados o comprometidos.
¿Qué mide y por qué
| Anomalía detectada | Criterio | Causa probable |
|---|---|---|
| Card stress event | Latencia > media × 3 (ETO_ANOMALY_FACTOR) | Tarjeta sobrecargada, posible DDoS sobre la tarjeta |
| Card degradation | Deriva continua de la media hacia arriba | Tarjeta envejeciendo - sustituir antes de fallo |
| Emulator detected | Varianza artificialmente baja (timing uniforme) | Software emulador - timing uniforme vs tarjeta real (variable) |
| Key change in progress | Distribución bimodal | Cambio de clave activo o dos tarjetas compartiendo línea |
Perfil estadístico
Cada perfil (eto_profile_t) rastrea un par (label, CAID) con:
- n_samples - número total de muestras registradas
- sum_ms / sum_sq_ms - suma y suma de cuadrados para calcular media y σ en integer aritmética
- min_ms / max_ms - latencias extremas registradas
- hist[16] - histograma de frecuencias, 16 cubos de 100ms cada uno (último: >1500ms)
- anomaly_count / last_anomaly_ms - contador de anomalías y última latencia anómala
Límite: ETO_MAX_PROFILES=64 pares simultáneos. La detección de anomalías requiere ≥ETO_MIN_SAMPLES=5 muestras.
Integración con ERD
El módulo ERD (ECM Replay Detector) consulta el ETO mediante eto_get_mean_ms(caid) para calcular el retardo sintético adaptativo. Si no hay suficientes muestras, ERD usa el valor por defecto configurado (erd_default_ms).
API
| Endpoint | Descripción |
|---|---|
GET /api/forensics/timing | JSON array con todos los perfiles ETO activos: label, CAID, muestras, media, σ, histograma, anomalías. Polling auto cada 2s en Forense. |
Config
| Campo | Default | Descripción |
|---|---|---|
| enable_eto | 1 | Activa el módulo ETO. Deshabilitar solo en sistemas muy limitados de RAM. |
🛡 CWS - CW Consensus Shield
GET /api/status/cws.Las operadoras con sistemas anti-cardsharing (Movistar+, Sky, Canal+) inyectan periódicamente CWs envenenadas: respuestas que pasan el checksum DVB pero contienen bytes incorrectos que hacen que la imagen salga corrupta o en negro. El CW Consensus Shield neutraliza este ataque.
Principio de funciónamiento
ECM → Peer A → CW: 01 23 45 67 ... ✓ (voto 1)
ECM → Peer B → CW: 01 23 45 67 ... ✓ (voto 2 - quórum alcanzado)
ECM → Peer C → CW: DE AD BE EF ... ✗ (diverge → Peer C penalizado HLS -5 score)
Mecanismo
- Acumulador de votos - al recibir
CMD_CW_RESP, antes de entregar al demux, registra la CW en un slot de votación indexado por el hash de la ECM. - Threshold de quórum - configurable (
cw_consensus_quorum, default 2). En cuanto N peers coinciden, entrega la CW ganadora inmediatamente. - Timeout de consenso - si en
client_timeout/2ms no hay quórum, entrega la CW del peer de mayor reputación HLS. - Penalización automática - peer que entregó CW no ganadora: -5 en
avg_latencyscore. Tras 3 penalizaciónes → deprioritizado 60s.
Diferencia con DoubleCheck
| DoubleCheck | CW Consensus Shield | |
|---|---|---|
| Objetivo | Verificar que al menos 2 peers devuelven la misma CW | Votación mayoritaria entre N peers con penalización automática |
| Quórum | Fijo: 2 | Configurable: cw_consensus_quorum |
| Penalización | No automática | Automática, íntegrada en HLS score |
| Contadores auditables | No | Sí: cws_poisoned_total / cws_poisoned_today |
Config y API
| Campo/Endpoint | Descripción |
|---|---|
| cw_consensus_quorum | Número de peers que deben concordar. Default: 2. Requiere tantos upstreams activos como quórum configurado. |
GET /api/status/cws | Contadores cws_poisoned_total y cws_poisoned_today (reset automático a medianoche). |
🎭 ERD - ECM Replay Detector
GET /api/forensics/replay.Cuando una ECM llega y ya está en caché, Candela la responde en <5ms. Las tarjetas físicas tardan ~300ms. Los operadores anti-piratería pueden detectar softcams lanzando ECMs de prueba y midiendo el tiempo de respuesta. ERD neutraliza este vector de detección.
Problema: fingerprinting por timing
| Fuente de CW | Latencia típica | ¿Detectable? |
|---|---|---|
| Tarjeta física local | 200–500ms | No (comportamiento normal) |
| Peer upstream P2P | 100–400ms | Difícil (variación normal) |
| Caché RAM sin ERD | <5ms | Sí - timing anómalamente corto |
| Caché RAM con ERD | ~media_ETO ± jitter | No - imita tarjeta física |
Implementación no bloqueante
ERD no bloquea ni crea hilos. Al detectar un cache hit, calcula el retardo y lo registra internamente. El motor de ECMs pendientes re-evalúa cada iteración y entrega la CW cuando el timer expira. Zero overhead adicional.
Cálculo del retardo
mean = eto_get_mean_ms(caid) // media ETO para la CAID
si mean == 0: mean = erd_default_ms // fallback configurable (default 300ms)
jitter = rand() % (2 × erd_jitter_pct + 1) − erd_jitter_pct // ej. ±20%
delay = mean × (100 + jitter) / 100
Estadísticas ERD
| Campo | Descripción |
|---|---|
| n_hits | Total de cache hits detectados |
| n_delayed | Cache hits a los que se aplicó retardo (ERD activo) |
| total_delay_ms | Suma acumulada de todos los retardos aplicados |
| last_delay_ms | Último retardo aplicado en ms |
| last_caid | CAID del último cache hit retardado |
Config
| Campo | Default | Descripción |
|---|---|---|
| enable_erd | 1 | Activa el ECM Replay Detector. Recomendado siempre activo. |
| erd_default_ms | 300 | Retardo base en ms cuando ETO no tiene datos para la CAID. |
| erd_jitter_pct | 20 | Jitter en % aplicado al retardo base. Ej: 20 = ±20% del retardo medio. |
🪄 CFI - CAS Fingerprint Inversion
GET /api/forensics/cfi. Activo por defecto. Sustituye a ERD cuando ambos están habilitados.CFI es la evolución directa del ERD. Donde ERD imita el tiempo medio de la tarjeta (~300ms), CFI imita el mínimo histórico plausible - el retardo más corto que la tarjeta real ha mostrado para ese CAID. El resultado es idéntico opacidad anti-fingerprinting con latencia percibida por el usuario hasta 6× menor.
ERD vs CFI - Diferencia clave
| Módulo | Objetivo del retardo | Ejemplo (CAID 0x0500) | Latencia añadida |
|---|---|---|---|
| ERD | Media ETO por CAID | ~300ms | Alta - cámara completa de la tarjeta |
| CFI | Mínimo ETO por CAID | ~50ms | Mínima - límite inferior de la tarjeta |
| Sin protección | - | <5ms | Cero - detectado por operadora |
Compensación de tiempo transcurrido
Si la ECM ya tardó más que el floor CFI (por ejemplo, un peer upstream que tardó 80ms y el floor es 50ms), CFI no añade retardo adicional - entrega inmediatamente. Esto es el modo passthrough y hace que CFI sea completamente transparente en carga de red alta.
floor = eto_get_min_ms(caid) // mínimo histórico ETO para la CAID
si floor == 0: floor = cfi_default_ms // fallback (default 50ms)
jitter = rand() % (2 × cfi_jitter_pct + 1) − cfi_jitter_pct // ej. ±15%
target = floor × (100 + jitter) / 100
delay = max(0, target − elapsed_ms) // tiempo ya transcurrido se descuenta
Precedencia CFI → ERD
Cuando ambos módulos están activos, CFI tiene precedencia. ERD solo actúa como fallback si CFI está desactivado. No se acumulan retardos.
Estadísticas CFI
| Campo | Descripción |
|---|---|
| n_hits | Total de cache hits procesados por CFI |
| n_delayed | Cache hits que requirieron retardo adicional |
| n_passthrough | Cache hits entregados sin retardo (elapsed ≥ target) |
| total_delay_ms | Suma acumulada de retardos aplicados |
| last_delay_ms | Último retardo aplicado en ms |
| last_caid | CAID del último cache hit procesado |
Config
| Campo | Default | Descripción |
|---|---|---|
| enable_cfi | 1 | Activa CFI. Cuando está activo, tiene precedencia sobre ERD en cache hits. |
| cfi_default_ms | 50 | Floor mínimo en ms cuando ETO aún no tiene datos para la CAID. |
| cfi_jitter_pct | 15 | Jitter ±% sobre el floor. Ej: 15 = ±15% del mínimo histórico. |
🔒 EFG - ECM Flow Guard
GET /api/forensics/cascade.Un peer legítimo puede zappear rápido por muchos canales - pero cada canal recibe solo 1-2 ECMs y luego silencio. Un peer que hace resharing mantiene varios canales con ECMs continuas cada ~10s (el crypto period habitual). EFG distingue ambos casos y protege la tarjeta física de banes por anti-cascading.
El problema: cascading detection
Los operadores rastrean cuántos SIDs distintos solicita una tarjeta en una ventana temporal. Una tarjeta que sirve muchos canales simultáneamente (resharing) genera una diversidad de SIDs estadísticamente imposible para un suscriptor legítimo. EFG detecta esto en el extremo Candela antes de que lo haga el operador.
Diferencia entre zapping y resharing
| Comportamiento | ECMs por SID | ¿Cuenta para EFG? |
|---|---|---|
| Zapping rápido (30 canales en 5s) | 1-2 por canal | No - ignorado por efg_min_ecms |
| Resharing activo (4 clientes simultáneos) | Continuas cada ~10s | Sí - cada SID supera efg_min_ecms |
Strict Cache Mode dinámico
Cuando EFG detecta que un peer supera el límite de SIDs activos configurado, activa Strict Cache Mode: el peer solo puede recibir CWs que ya estén en caché. Las peticiónes que requieran tarjeta física son denegadas - protegiendo la tarjeta sin cortar el servicio. El modo expira automáticamente tras el período configurado.
Implementación técnica
- Ring buffer lock-free - estado embebido directamente en la estructura interna de cada peer. Sin malloc, sin free.
- O(1) hot path -
efg_record_sid()esstatic inline. Zero overhead de llamada en el camino crítico de ECM. - Lazy expiry - las entradas expiradas se limpian solo cuando se evalúa un nuevo SID, no en cada ECM.
- Thread-safe sin mutex - el índice de escritura usa operaciónes atómicas para ser thread-safe sin bloqueos.
- Auto-recovery - al expirar el timer de penalización, el peer vuelve a modo normal automáticamente con log de recuperación.
Config
| Campo | Default | Descripción |
|---|---|---|
| enable_efg | 1 | Activa ECM Flow Guard. Desactivar solo para debug. |
| efg_max_sids | configurable | Número máximo de SIDs activos antes de activar Strict Cache Mode. |
| efg_min_ecms | 2 | Mínimo de ECMs que debe recibir un SID para considerarse "activo" (filtra zapping). |
| efg_window_sec | configurable | Ventana temporal en segundos para evaluar SIDs activos. |
| efg_penalty_sec | configurable | Duración del Strict Cache Mode tras detectar cascading. |
API
| Endpoint | Descripción |
|---|---|
GET /api/forensics/cascade | Configuración activa de EFG en JSON: enabled, max_sids, min_ecms, window_sec, penalty_sec, ring_size. |
🔍 CWRID - CW Replay & Injection Detector
GET /api/forensics/cwrid.Detecta dos patrónes de abuso de CW en tiempo real usando una ventana deslizante de hashes (SHA256 truncado a 8 bytes):
- CW Replay: la misma CW aparece asociada a ECMs distintas o canales distintos dentro de la ventana. Indica reutilización de CW pre-grabada o inyección de CW estática por un peer malicioso.
- Lateral Sharing: la misma CW se entrega a más de un SRVID diferente. Dentro del mismo canal es normal (simulcrypt); si los SRVIDs son distintos indica resharing encubierto.
Implementación
Ventana deslizante de 32 entradas. Cada entrada almacena el hash SHA256[:8] de la CW, CAID, hasta 4 SRVIDs distintos y los timestamps de primera y última aparición. Cuando la ventana está llena se reemplaza la entrada más antigua. Sin malloc: array estático.
Config
| Campo | Default | Descripción |
|---|---|---|
| enable_cwrid | 1 | Activa el detector CWRID. |
| cwrid_window_sec | 30 | Ventana en segundos. Las CWs más antiguas que este valor se descartan del análisis. |
API
| Endpoint | Descripción |
|---|---|
GET /api/forensics/cwrid | JSON con stats globales (cw_checked, replay, lateral) + lista de hasta 64 eventos recientes con hash, CAID, SRVID y tipo de detección. |
📊 EEA - ECM Entropy Analyzer
GET /api/forensics/entropy.Calcula la entropía de Shannon de los bytes de cada CW por CAID. Una CW generada por un CAS legítimo es prácticamente aleatoria (≈8.0 bits/byte). Una CW con entropía baja indica:
- Fake CW inyectada por peer malicioso (ej:
0x00×16,0xFF×16) - CW mal descifrada por corrupción de clave en el CAS local
- CAS en modo de fallo devolviendo un valor fijo
El umbral de alerta es 7.0 bits/byte. Las alertas solo se emiten a partir de 5 muestras para evitar falsos positivos en el arranque.
Config
| Campo | Default | Descripción |
|---|---|---|
| enable_eea | 1 | Activa el análisis de entropía de CW. Sin impacto en rendimiento - cálculo matemático puro. |
API
| Endpoint | Descripción |
|---|---|
GET /api/forensics/entropy | JSON array con un perfil por CAID: muestras, alertas, entropía última/media/mín/máx, umbral y timestamp de última muestra. |
⏳ ECLD - ECM Chain Latency Decomposer
GET /api/forensics/chain.Registra los timestamps de las 5 etapas del ciclo de vida de cada ECM para descomponer la latencia total en sus componentes:
| Etapa | Descripción | Desglose |
|---|---|---|
| T0 | ECM recibida del DVB-API o peer | - |
| T1 | Búsqueda en caché completada (hit o miss) | T1−T0 = cache_lookup_ms |
| T2 | ECM envíada al upstream (peer o lector local) | - |
| T3 | CW recibida del upstream | T3−T2 = upstream_rtt_ms |
| T4 | CW entregada al demux | T4−T3 = delivery_ms; T4−T0 = total_ms |
Los datos se almacenan en un ring buffer de 64 cadenas completadas. Las cadenas que usan caché no tienen T2/T3 (RTT upstream = 0). Las estadísticas acumuladas incluyen media de total_ms, RTT upstream medio, y ratio de cache hits.
Config
| Campo | Default | Descripción |
|---|---|---|
| enable_ecld | 1 | Activa el decompositor de latencia. El overhead es mínimo (4 asignaciones de timestamp por ECM). |
API
| Endpoint | Descripción |
|---|---|
GET /api/forensics/chain | JSON con estadísticas globales + array de hasta 64 cadenas completadas con CAID, SRVID, hash ECM, desglose de latencia por etapa y fuente upstream. |
🛡 OLG - ECM Overlap Guard
Previene pantallas negras durante el cambio de criptoperíodo. El problema: entre que el demux solicita una nueva CW y el upstream la entrega pueden pasar entre 100ms y 2s. Si la CW anterior ya expiró, el demux queda sin descifrar y aparece pantalla negra.
Cómo funcióna
OLG mantiene una tabla de la última CW válida entregada por canal (CAID × SRVID, hasta 256 entradas). Cuando llega una ECM que no está en caché, antes de encolar la petición al upstream, OLG entrega inmediatamente la última CW conocida al demux. El demux puede seguir descifrando mientras llega la nueva CW.
Integración con Adaptive Timeout
El timeout de ECM es ahora adaptativo: usa la media ETO × 3 por CAID, con mínimo de 500ms y sin superar el timeout global. Esto complementa a OLG: los canales con upstream lento no se cortan prematuramente, y mientras el upstream trabaja el demux tiene la CW de soporte de OLG.
Config
| Campo | Default | Descripción |
|---|---|---|
| enable_overlap_guard | 1 | Activa el ECM Overlap Guard. Recomendado siempre activo para evitar micro-cortes en el cambio de período. |
| overlap_guard_max_age_ms | 10000 | Antigüedad máxima en ms de la CW de soporte. Si la última CW del canal es más antigua que este valor, no se entrega como puente (evita usar claves expiradas de hace mucho tiempo). |
🔒 CTC - Candela Transport Camouflage
enable_tls_camouflage solo controla el handshake en conexiónes salientes.El problema que resuelve
Los ISPs activan un modo "lista blanca" durante eventos de alta demanda (fútbol, F1, Fórmula E): en lugar de intentar leer el contenido, el DPI bloquea directamente cualquier conexión TCP cuyo perfil de tráfico no encaje en un protocolo conocido y aprobado. Alta entropía uniforme + longitud de paquetes no estándar = corte inmediato. No necesitan saber qué es. Si no lo reconocen, lo tiran.
El anti-DPI estocástico de Candela (ChaCha20, padding aleatorio, jitter, LZ4) hace el payload ilegible y dificulta la correlación, pero no resuelve el bloqueo por perfil de tráfico. CTC añade la capa de presentación que faltaba: framing TLS Application Data indistinguible de HTTPS real. Los vectores restantes - distribución estadística de tamaños de paquete, patrón temporal de ECMs, ausencia de tráfico de fondo y duración de sesión TCP - quedan cubiertos por el módulo Anti-DPI Suite (TAR), implementado en R37. Con CTC + CPM + TAR activos, la cobertura anti-DPI es del 100%.
Cómo funcióna
CTC envuelve cada paquete Candela en un TLS Application Data record estándar. Para el DPI es tráfico HTTPS/TLS estándar. El payload interno sigue siendo ChaCha20+Poly1305, con entropía indistinguible de datos TLS cifrados reales. El overhead es mínimo - unos pocos bytes por paquete más un handshake inicial.
Handshake de sesión
Al conectar, se intercambia un par ClientHello/ServerHello TLS 1.3 sintético (estructuralmente válido para DPI, no funciónal como TLS real):
- ClientHello: cipher suites TLS_AES_128_GCM / AES_256_GCM / CHACHA20, Random[32] aleatorio (distinto en cada sesión), extensiones
supported_versions+supported_groups(x25519) + SNI opcional. - ServerHello: respuesta sintética equivalente.
- A partir de ahí: framing TLS Application Data en cada paquete Candela.
Retrocompatibilidad automática
El servidor detecta automáticamente si el cliente soporta CTC mediante MSG_PEEK del primer byte de la conexión:
0x16(TLS Handshake) → peer R34 o superior → ejecuta handshake → activa framing- Cualquier otro byte → peer legacy (anterior a R34) → modo legacy sin framing, sin coordinación manual
Los clientes legacy (anterior a R34) siguen conectándose y funciónando sin cambios.
SNI - sin apuntar a dominios ajenos
Valor ctc_sni | Comportamiento |
|---|---|
auto (default) | Genera un hostname sintético basado en el NodeID: primeros 6 chars hex + .cdn-cache.net (ej: a1b2c3.cdn-cache.net). No existe en DNS, no pertenece a nadie. |
"" (vacío) | Sin extensión SNI. Válido en TLS 1.3; muchos clientes corporativos lo omiten. |
mi.dominio.com | El operador usa su propio dominio si dispone de uno. |
Implementación técnica
- Envío:
writev()scatter/gather en POSIX -iovec[0]= 5 bytes cabecera en stack,iovec[1]= payload Candela original. Ceromemcpy, ceromalloc. - Recepción: máquina de estados
ctc_strip()por peer - gestiona fragmentación TCP correctamente. - Windows: buffer en stack MTU-safe (no hay
writev). - Sin OpenSSL TLS real: solo
RAND_bytesya enlazado. Cero dependencias nuevas.
Límites del diseño
Config
| Campo | Default | Descripción |
|---|---|---|
| enable_tls_camouflage | 1 | Activa el handshake CTC en conexiónes salientes. La detección entrante (MSG_PEEK) es siempre activa. No desactivar en redes R34 o superior. |
| ctc_sni | auto | SNI del ClientHello: auto (sintético desde NodeID), vacío (sin SNI), o hostname propio. |
🔁 ECDH Rekey - Rotación de sesión cada 24h
El problema que resuelve
El intercambio ECDH X25519 genera una session_key efímera única por conexión. Si un peer permanece conectado 7 días, esa clave protege todo el tráfico de esa sesión. Si alguien compromete esa clave en memoria, puede descifrar toda la sesión pasada (sin PFS dentro de la sesión).
Solución: Rekey in-session a las 24h
El watchdog del servidor detecta automáticamente sesiones con connected_at > 86400s. La rotación se hace de forma diferente según el rol del peer:
- Peer entrante (cliente conectado a nosotros): el servidor inicia un nuevo intercambio ECDH usando los mismos comandos
CMD_ECDH_INIT/RESP/ACK, pero sobre la sesión activa. La TCP no se corta. El cliente responde con su nueva clave pública. Ambos derivan el nuevo secreto compartido y activan la nueva clave sin interrupción perceptible. - Peer saliente (servidor al que nos conectamos): se desconecta limpiamente. El watchdog de reconexión inicia una nueva sesión TCP completa, con nuevo ECDH desde cero. El servidor remoto también aplica su rekey in-session a esa nueva conexión.
Mecanismo técnico
El rekey reutiliza la misma máquina de estados ECDH de R30, extendida para sesiones activas:
- Servidor genera nuevo par X25519 → almacena privkey en
peer->ecdh_priv - Servidor envía
CMD_ECDH_INIT(nueva pubkey) al cliente por el canal existente (cifrado con clave actual) - Cliente genera nuevo par → deriva secreto → guarda en
pending_key(modo 1) → responde conCMD_ECDH_RESP(cifrado con clave antigua) - Servidor recibe RESP → deriva secreto → activa nueva clave inmediatamente → guarda antigua como residual (modo 2) → envía
CMD_ECDH_ACK(cifrado con clave nueva) - Cliente recibe ACK con clave nueva → mecanismo Fallback AEAD activa
pending_key→connected_atse reinicia → timer de 24h vuelve a cero
Guard anti-doble-envío: Si llega un tick del watchdog antes de que el cliente responda (ecdh_priv != NULL), el servidor no envía un segundo ECDH_INIT.
Nodos virtuales (sin tarjeta física)
Los nodos que actúan como relay o proxy (sin lector físico propio) anuncian las tarjetas de sus upstream mediante CMD_CARD_MAP con hop=N+1. El campo max_hops de la cuenta de cada cliente controla hasta qué profundidad de hop puede ver ese cliente:
max_hops=0→ solo tarjetas físicas del nodo (hop 0)max_hops=1→ hop 0 + lo que el nodo obtiene de sus upstream directos (hop 1)max_hops=N→ hasta N hops de profundidad
Los peers con hop > 10 se descartan para evitar propagación anómala.
Failban anti-CGNAT
Cuando un peer autentica correctamente, se limpia el contador de intentos fallidos de su IP. Esto evita que en redes con CGNAT (múltiples peers compartiendo la misma IP pública) un peer con credenciales incorrectas banee involuntariamente a otros peers legítimos en la misma IP.
| Parámetro | Valor | Descripción |
|---|---|---|
| FAILBAN_MAX_ATTEMPTS | 10 | Intentos antes de bloqueo. Cubre el backoff exponencial completo del watchdog (1+2+4+8+16+30s). |
| FAILBAN_DECAY_SECS | 900 | Ventana de 15 minutos sin intentos para resetear el contador automáticamente. |
🫀 CPM - Adaptive Pulse Masking
enable_pulse_masking = 1). Sin hilos adicionales.El problema que resuelve
El Fake TLS 1.3 (CTC) oculta el contenido de los paquetes, pero no oculta el ritmo. El cardsharing tiene una firma temporal inconfundible: una petición de ~150 bytes y una respuesta de ~32 bytes exactamente cada 10-15 segundos (el criptoperíodo DVB). Un DPI avanzado no necesita leer el paquete - si ve ese patrón de silencio/ráfaga/silencio a intervalos regulares, identifica el servicio y puede actuar.
Solución: Adaptive Chaffing
Por cada peer autenticado, el sistema monitoriza el tiempo desde el último envío real (last_tx_time). Si el silencio supera un umbral aleatorio de 2.0 a 3.5 segundos, se inyecta un paquete de relleno (CMD_PADDING) con payload pseudoaleatorio de 200 a 1400 bytes. El resultado: el DPI ve una conexión TLS con tráfico continuo y variable. El latido de 10s queda enterrado.
Diseño técnico
- PRNG xorshift32: no bloqueante, cero syscalls, ~1ns/llamada. Seed con
clock_gettime(MONOTONIC) ^ getpid()en el arranque. Distinto en cada proceso. - Sin hilos adicionales: la evaluación se hace en el bucle watchdog existente (~250ms de resolución). Cero
pthread_create. - Intervalo desfasado por peer:
next_chaff_msse renueva aleatoriamente tras cada chaff, evitando ráfagas síncronas cuando hay muchos peers. - Cifrado estándar: el chaff pasa por
proto_send_packet()→ LZ4 + ChaCha20-Poly1305 + CTC si está activo. Indistinguible de tráfico real. - Coste por peer: ~1 paquete/2.75s × 800 bytes promedio ≈ 2.3 kbps. En un router MIPS con 5 peers: ~11.5 kbps total. En un VPS con 100 peers: ~230 kbps - perfectamente asumible.
Campos añadidos a candela_peer_t
| Campo | Tipo | Descripción |
|---|---|---|
| last_tx_time | uint64_t | Timestamp (ms monotónico) del último paquete envíado. Actualizado en proto_send_packet(). |
| next_chaff_ms | uint16_t | Intervalo hasta el próximo chaff [2000-3500ms]. Renovado aleatoriamente tras cada envío. |
Config
| Campo | Default | Descripción |
|---|---|---|
| enable_pulse_masking | 1 | Activa el Adaptive Pulse Masking. Desactivar solo en entornos con ancho de banda muy limitado y sin riesgo de DPI avanzado. |
🎭 DPM - Decoy Port Multiplexing
enable_dpm = 1). Zero overhead en peers legítimos.El problema que resuelve
Cualquier escáner de red (Shodan, ZMap, Censys, herramientas de ISP) que encuentre el puerto P2P de Candela puede identificarlo mediante un banner grab: el primer byte no es un verbo HTTP ni un handshake TLS reconocido, por lo que queda clasificado como "protocolo desconocido de alta entropía". Esta clasificación puede atraer atención indeseada o desencadenar bloqueos automáticos.
Solución: respuesta HTTP falsa
El servidor inspecciona los primeros 4 bytes de cualquier conexión entrante no autenticada que no haya iniciado un handshake CTC. Si coincide con un verbo HTTP (GET , POST, HEAD, OPTI, PUT , DELE, CONN), responde con una página nginx plausible y cierra inmediatamente la conexión.
Respuesta envíada
HTTP/1.1 200 OK
Server: nginx/1.24.0
Content-Type: text/html; charset=utf-8
Content-Length: 97
Connection: close
<!DOCTYPE html><html><head><title>Home</title></head>
<body><p>Service unavailable.</p></body></html>
Diseño técnico
- Detección:
memcmpde 4 bytes - sin parsing HTTP completo. Cero asignaciones dinámicas. - Condiciones: peer no autenticado +
ctc_active == 0+bytes_read >= 4. Un peer Candela legítimo nunca envía un verbo HTTP. - Respuesta estática:
static const char dpm_resp[]- compilada en el binario, sin ficheros externos. - Coste en peers legítimos: cero. La condición falla en la primera comprobación (peer autenticado o CTC activo).
Config
| Campo | Default | Descripción |
|---|---|---|
| enable_dpm | 1 | Activa Decoy Port Multiplexing. El puerto P2P responde como nginx a escáneres HTTP. |
🎯 Anti-Scanner - Honeypot CAIDs + CAID Probe Detection
Honeypot CAIDs
Los Honeypot CAIDs son valores de CAID ficticios configurados como trampa. Ningún canal real de TV existe con estos CAIDs, por lo que cualquier peer que solicite un ECM con uno de ellos es, con 100% de certeza, un scanner, bot o cliente malicioso.
| Característica | Detalle |
|---|---|
| Detección | Comparación O(1) en el handler CMD_ECM_REQ antes de intentar resolver la ECM. |
| Reacción | Ban inmediato en failban + desconexión del peer + evento P2P:honeypot en el panel de seguridad. |
| Visibilidad | El evento aparece en la pestaña 🔔 Alertas del panel lateral con IP, usuario y CAID solicitado. |
| Falsos positivos | Cero. Un STB legítimo nunca envía ECMs con CAIDs inventados. |
Configuración de Honeypot CAIDs
| Campo | Default | Descripción |
|---|---|---|
honeypot_caids | "" | Lista de CAIDs falsos en hex separados por coma. Ejemplo: FFF1,FFF2,DEAD,BEEF. Vacío = desactivado. |
0xFFF0–0xFFFF, 0xDEAD, 0xBEEF son seguros. Evitar 0x0000 (CAID nulo, usado internamente).Anti-Probing - Detección de scanners por CAID
Un STB real que descifra TV siempre solicita ECMs de los mismos 1–3 CAIDs (los del canal sintonizado). Un bot que enumera las capacidades del servidor prueba sistemáticamente decenas de CAIDs distintos en pocos segundos - esa diversidad estadística es la firma del probing.
| Característica | Detalle |
|---|---|
| Método | Ventana deslizante de CAIDs únicos por peer: probe_caids[32] + contador + timestamp en candela_peer_t. |
| Trigger | Si probe_caid_count ≥ probe_caid_threshold dentro de probe_caid_window_secs → ban + expulsión. |
| Reacción | Failban + desconexión. Evento P2P:caid_probe en el panel de seguridad. |
| Protección vs falsos positivos | El umbral por defecto (8 CAIDs / 60s) tolera perfectamente el zapping rápido entre canales de distintos bouquets. |
Configuración de Anti-Probing
| Campo | Default | Descripción |
|---|---|---|
probe_caid_threshold | 8 | CAIDs únicos en la ventana antes de banear. 0 = desactivado. |
probe_caid_window_secs | 60 | Duración de la ventana deslizante en segundos. |
ECDH-first Handshake (Protocolo v2)
Además de los mecanismos activos de detección de scanners, el Protocolo v2 garantiza que las credenciales de usuario nunca viajan bajo la clave bootstrap conocida.
Cliente ──[0x42 bootstrap]──► CMD_ECDH_INIT (pubkey X25519)
Servidor ◄──[0x42 bootstrap]── CMD_ECDH_RESP (pubkey X25519)
════════ [Clave ECDH efímera activa] ════════
Cliente ──[ECDH key]──► CMD_ECDH_ACK
Cliente ──[ECDH key]──► CMD_HELLO (usuario + contraseña)
Servidor ◄──[ECDH key]── CMD_HELLO_ACK
════════ [Sesión autenticada] ════════
El servidor rechaza cualquier CMD_HELLO que llegue sin ECDH previo activo, registrando el evento en failban (P2P:hello_no_ecdh). Un cliente de protocolo <v2 no puede autenticarse.
Nonce monotónico anti-colisión
El nonce ChaCha20 de 12 bytes incorpora un contador monotónico por peer (tx_nonce_ctr, uint64_t) en sus primeros 8 bytes (XOR). Esto garantiza unicidad matemática entre paquetes dentro de una sesión sin depender únicamente de la aleatoriedad, eliminando la probabilidad de colisión por birthday paradox incluso en sesiones de ultra-larga duración.
🕸️ PIR - Peer Intelligence Ring
GET /api/security/pir · GET /api/security/watchlist · GET /api/peers/discovered.Cada nodo Candela defiende solo su propio perímetro. Con PIR la red se convierte en un sistema inmune distribuido: cuando un nodo detecta un scanner, ataque honeypot o fallo AEAD, comparte el evento con todos sus peers autenticados vía CMD_REP_SHARE. Los peers receptores añaden la IP a su watchlist local. Si esa IP intenta conectarse a ellos en las próximas 24h, ya están en alerta máxima.
Flujo de inteligencia colectiva
Nodo A detecta scanner IP X → failban + pir_do_broadcast(X, PIR_EVT_CAID_PROBE)
→ CMD_REP_SHARE enviado a todos los peers autenticados con ECDH activo
→ Nodo B recibe → pir_receive_threat() → X añadida a watchlist local (TTL 24h)
→ Si X intenta conectar a B → pir_check_watchlist() → alerta preemptiva en panel
Tipos de evento compartidos
| Código | Nombre | Severidad | Origen |
|---|---|---|---|
| 0x01 | caid_probe | 3 - alto | Anti-probing: rotación de CAIDs |
| 0x02 | honeypot | 4 - crítico | CAID trampa activado |
| 0x03 | bruteforce | 2 - medio | Fuerza bruta de login |
| 0x04 | fakecw | 2 - medio | CW falsa detectada |
| 0x05 | aead_fail | 2 - medio | Fallo descifrado AEAD |
| 0x06 | cascade | 2 - medio | Anti-cascade EFG |
| 0x07 | scanner | 1 - bajo | Escaner anónimo |
Rate limiting y anti-spam
Máximo pir_rate_limit eventos por minuto emitidos (default 5). En caso de ataque DDoS masivo que genere miles de events/segundo, PIR reduce automáticamente su emisión para no saturar los canales P2P con inteligencia.
Descubrimiento de peers - CMD_PEER_DISC (legacy)
Los peers con proto_ver < 35 envían CMD_PEER_DISC con hasta 16 peers conocidos. Los nodos modernos (v35+) lo procesan como entrada NETMAP (hops=1). Reemplazado por CMD_NET_MAP en proto_ver 35.
Config
| Campo | Default | Descripción |
|---|---|---|
| enable_pir | 1 | Activa el Peer Intelligence Ring. |
| pir_watchlist_ttl_h | 24 | TTL en horas de las IPs en la watchlist local. |
| pir_rate_limit | 5 | Max eventos de seguridad a emitir por minuto. |
| pir_auto_connect | 0 | Añade peers entrantes a pir_discovered[] y los propaga via CMD_PEER_DISC cada 60s. Marca el nodo como contribuidor (NRS +10, icono 🔥). Incompatible con anon_peer_ips=1. |
🏠 LAN Discovery - Detección local UDP
Módulo que detecta automáticamente otras instancias de Candela en la misma red local (LAN) sin necesidad de configurarlas manualmente. Los peers descubiertos se muestran en el WebIf como candidatos a añadir en Config > Servidores.
Cómo funcióna
Al arrancar, Candela lanza un hilo de fondo (lan_disc_thread) que:
- Abre un socket UDP con
SO_BROADCAST + SO_REUSEADDR + SO_REUSEPORTenlazado al puerto 52700. - Cada 60 segundos envía un beacon UDP broadcast a
255.255.255.255:52700con el formato:
CANDELA_LAN_V1:<NodeID>:<puerto_p2p>:<nombre_operador>\n - Escucha beacons de otras instancias y los almacena en un ring buffer de 16 entradas con TTL de 300 segundos.
- Filtra el propio beacon por NodeID para no añadirse a sí mismo.
Vista en WebIF
En la pestaña Mapa de Red, cuando hay peers descubiertos, aparece debajo de la tabla NETMAP una sección 🏠 Detectados en la LAN con:
- Nombre del operador (o NodeID si no tiene nombre)
- IP:puerto P2P anunciado
- NodeID (si está disponible)
API
GET /api/peers/lan
Devuelve array JSON: [{"ip":"192.168.1.5","port":15000,"nodeid":"9F4E...","name":"Peer1","last_seen":1714500000}]
Archivos
| Archivo | Descripción |
|---|---|
src/utils/lan_disc.c | Implementación completa del módulo |
src/utils/lan_disc.h | API pública: lan_disc_init(), lan_disc_stop(), lan_disc_get_json() |
Config
| Parámetro | Valor | Descripción |
|---|---|---|
LAN_DISC_PORT | 52700 | Puerto UDP para el beacon. Compartido por todas las instancias en la LAN. |
LAN_DISC_MAX_PEERS | 16 | Tamaño del ring buffer de peers descubiertos. |
LAN_DISC_TTL | 300s | Tiempo máximo sin beacon antes de eliminar un peer del buffer. |
🗺 NETMAP - Network Topology Map
GET /api/peers/netmap. Página dedicada: candela_netmap.html.Descubrimiento de la topología completa de la red Candela mediante gossip P2P puro. Un nodo con un solo peer conocido aprende automáticamente la existencia de todos los demás nodos de la red. Cero credenciales viajan nunca - solo metadatos públicos (IP, puerto, nombre de operador, país, versión de protocolo), cifrados y autenticados con ECDH.
Comando CMD_NET_MAP = 0x16 (formato R38+)
Solo se acepta de peers con ECDH activo y autenticados. Payload:
[0-1] count uint16 BE (max 128 entradas)
[2+n×53] entradas (53 bytes cada una, sin IP ni puerto):
[0-15] nodeid[16] NodeID binario (hex string decodificado)
[16-17] proto_ver[2] BE
[18-49] name[32] operator_name null-terminated (ASCII 0x20-0x7E)
[50-51] country[2] ISO 3166-1 alpha-2
[52] flags[1] bit0=contributor (pir_auto_connect activo)
bit1=legacy_proto (NewCamd/MGcamd server activo) R40
CMD_NODE_INFO = 0x1A (formato R38+)
Enviado tras CMD_HELLO_ACK para anunciar metadatos propios al peer directo. 53 bytes:
[0-3] ip[4] IPv4 (uso interno: baneos y acciones locales, nunca sale a la red)
[4-5] port[2] BE
[6] proto_ver version de protocolo
[7-38] name[32] operator_name
[39-40] country[2] ISO 3166-1 alpha-2
[41-42] nrs[2] NRS score BE (x100)
[43-74] nodeid[32] hex string
[52] flags[1] bit0=pir_auto_connect, bit1=anon_peer_ips, bit2=legacy_proto R40
Reglas de gossip
- Solo se envía a peers con
ecdh_active=1yauthenticated=1. - Al recibir
CMD_NET_MAP, el nodo actualiza su tabla y reenvía solo si al menos una entrada es nueva o ha cambiado (R39 - evita bucles infinitos de retransmision). - Tras
CMD_HELLO_ACKse envía inmediatamente el mapa completo al nuevo peer. - TTL de cada entrada: 24 horas desde
last_seen. Expiradas → inactivas. - Los nodos
PEER_INCOMING(clientes entrantes) son visibles en el NETMAP global desde R38. - R40 Si un nodo tiene el flag
legacy_proto=1(NewCamd/MGcamd server activo), este dato se propaga como cambio relevante y desencadena reenvío gossip. El flag se almacena ennetmap_entry_t.legacy_protoy se expone en/api/peers/netmapcomo campolegacy_proto.
GSP - Gossip Selective Propagation (R39)
Sin GSP, cada CMD_NET_MAP envíaba la tabla completa de nodos conocidos, permitiendo a un actor con multiples peers autenticados enumerar toda la red en pocas peticiónes. GSP limita cuántas entradas se incluyen en cada gossip usando un shuffle aleatorio.
- Cada
CMD_NET_MAPincluye como máximonetmap_gossip_maxentradas (default 30), selecciónadas aleatoriamente con Fisher-Yates parcial sobre la tabla completa. - El PRNG del shuffle se inicializa con
RAND_bytesen cada arranque (no predecible entre sesiones). - Con
netmap_gossip_max=30y una red de N nodos, un observador necesita del orden de N/30 peticiónes para enumerar todos los nodos, en lugar de recibirlos de golpe.
Config
| Campo | Default | Descripción |
|---|---|---|
| node_country | "" | Pais del nodo (ISO 3166-1 alpha-2, ej. ES). Se anuncia en CMD_NET_MAP. |
| netmap_gossip_max | 30 | GSP: máximo de entradas por CMD_NET_MAP. 0 = sin límite (envía tabla completa). |
| pir_auto_connect | 0 | Añade peers entrantes descubiertos a pir_discovered[] y los propaga cada 60s. Marca el nodo como contribuidor (flag en CMD_NET_MAP y NRS +10). Bloqueado automáticamente si anon_peer_ips=1. |
| anon_peer_ips | 0 | Desactiva pir_auto_connect aunque este configurado, para no filtrar IPs reales de peers entrantes. |
📡 NSS - Node Status Signal
enable_nss=1).Cuando un nodo Candela se apaga de forma ordenada (SIGTERM/SIGINT), anuncia su baja a todos sus peers mediante CMD_GOING_DOWN = 0x15. Los receptores reinician inmediatamente el contador de reconexión sin esperar el timeout de socket (30–60s), eliminando la pantalla negra en apagados planificados.
Flujo
SIGTERM → main() → proto_broadcast_going_down()
→ itera peer_list[] → envía CMD_GOING_DOWN a peers auth+ECDH
→ receptor: server_next_retry_at=0, server_reconnect_delay=MIN
→ watchdog siguiente ciclo → connect() inmediato
Config
| Campo | Default | Descripción |
|---|---|---|
| enable_nss | 1 | Activa el Node Status Signal en el shutdown. |
⭐ NRS - Node Reputation Score
GET /api/peers/nrs. Activo por defecto (enable_nrs=1).Cada servidor upstream recibe una puntuación de reputación 0–100 basada en su comportamiento histórico. El watchdog de reconexión ordena los servidores por NRS descendente - el de mayor score se intenta primero.
Fórmula
base = 0.50 × latency_score + 0.30 × stability_score + 0.20 × activity_score
score = 50 + confianza × (base - 50)
latency_score = max(0, 100 - avg_latency_ms / 5)
stability_score = connect_ok / (connect_ok + connect_fail) × 100
activity_score = min(ecm_delivered, 100)
confianza = min(n_muestras, 10) / 10 (0.0 a 1.0)
Un nodo nuevo comienza con score neutro (50). El factor de confianza hace que el score converja gradualmente hacia el valor real segun acumula historial (~10 muestras para confianza plena). Latencia actualizada con EWMA (a=0.2) en cada CMD_CW_RESP.
Bonus contribuidor (R38)
Los nodos con pir_auto_connect=1 y anon_peer_ips=0 son marcados como contribuidores: comparten peers descubiertos con la red. Reciben +10 puntos de bonus sobre su NRS Score (tope 100). En el WebIF aparecen con icono 🔥 en el mapa de red y en la lista de peers. El flag se propaga en CMD_NODE_INFO y CMD_NET_MAP.
Penalización legacy protocol (R40)
Los nodos que tienen activo un servidor NewCamd o MGcamd (newcamd_servers/mgcamd_servers con enabled=1) anuncian el flag legacy_proto en CMD_NODE_INFO y CMD_NET_MAP. Los peers que reciben este flag aplican una penalización de -8 puntos sobre el NRS Score de ese nodo (tope inferior 0). El flag se actualiza en tiempo real: si el operador desactiva los servidores legacy, la penalización desaparece en el siguiente anuncio.
En el WebIF el nodo afectado aparece con el icono 🔓 (candado abierto) junto al score NRS. El icono es visible tanto en el panel compacto de nodos como en la tabla completa del mapa de red. El tooltip indica el motivo. La penalización no excluye al nodo de AMPE, solo lo relega en el ranking respecto a nodos equivalentes sin legacy activo.
Eventos registrados
| Función | Cuándo |
|---|---|
nrs_record_connect() | Tras CMD_HELLO_ACK éxitoso |
nrs_record_connect_fail() | TCP connect() fallido |
nrs_record_disconnect() | Peer eliminado (PEER_OUTGOING) |
nrs_record_ecm() | Tras cada CMD_CW_RESP |
nrs_record_legacy_proto() | Tras CMD_NODE_INFO con flag bit2 R40 |
Config
| Campo | Default | Descripción |
|---|---|---|
| enable_nrs | 1 | Activa Node Reputation Score. |
| pir_auto_connect | 0 | Activa el rol contribuidor: el nodo comparte peers descubiertos y recibe +10 NRS bonus (icono 🔥). |
🛡 Anti-Eclipse
max_peers_per_subnet.Un atacante que controle suficientes nodos puede saturar la lista de peers de la víctima con nodos propios del mismo bloque IP, aislándola de la red real (ataque Eclipse). Anti-Eclipse limita cuántos peers activos pueden pertenecer al mismo bloque /24.
Funcionamiento
El watchdog verifica antes de cada intento de conexión cuántos peers activos ya provienen del mismo /24 que el servidor candidato (ip & 0xFFFFFF00). Si el recuento ≥ max_peers_per_subnet, el candidato se omite en ese ciclo.
Config
| Campo | Default | Descripción |
|---|---|---|
| max_peers_per_subnet | 2 | Máx. peers activos del mismo bloque /24. 0 = sin límite. |
⚡ AMPE - Adaptive Multi-Path ECM
Extensión del motor HLS que consulta varios peers en paralelo por cada ECM en lugar de uno solo. La primera CW válida que llegue se entrega al receptor. El objetivo es eliminar los cortes de imagen cuando el peer prioritario tiene un pico de latencia puntual.
El problema que resuelve
Con ecm_multipath=1 (modo clásico), si el peer con mejor score tarda más de lo esperado (saturación, jitter de red), el receptor espera y puede producirse un corte. AMPE lanza la petición a N peers simultáneamente: si el primero tarda, el segundo o tercero ya tienen la respuesta lista.
Cómo funcióna
- En cada tick del watchdog (~250ms), el motor HLS ordena todos los peers elegibles por score.
- Con AMPE activo, en lugar de envíar
CMD_ECM_REQsolo al top-1, lo envía a los top-N (segúnecm_multipath). - Todos los peers envíados se marcan en
tried_peers_mapdel slot ECM, evitando reenvíos duplicados en el mismo tick. - La primera
CMD_CW_RESPválida que llegue se procesa según la lógica normal (CWS, ERD, FakeCW check). Las respuestas tardías de los otros peers actualizan igualmente suavg_latency.
Valores de ecm_multipath
- 0 — todos los peers elegibles reciben la ECM simultáneamente. Maxima redundancia; util en nodos de alta disponibilidad.
- 1 — modo clasico: un solo peer por ECM (comportamiento previo a AMPE).
- 2, 3, 4... — top-N peers por score reciben la ECM en paralelo. El valor 3 es el defecto desde R42.
No hay límite superior: cualquier valor entero positivo es válido. El motor envía solo a los peers disponibles; si hay menos de N, envía a todos sin generar peticiónes vacías.
Efecto en el scoring HLS
El scoring HLS sigue aprendiendo de forma correcta con AMPE:
- El peer ganador (más rápido) actualiza su
avg_latencycon el tiempo real. - Los peers que responden (aunque lleguen tarde) también actualizan su latencia si el slot ECM todavía está activo.
- Los peers que no responden (timeout) reciben la penalización existente.
En la práctica, el scoring converge más rápido porque se obtienen N datos de latencia por ECM en lugar de 1.
Coste en red
Con ecm_multipath=N se multiplica por N el tráfico de peticiónes ECM al upstream. En redes con pocos peers disponibles el motor adapta el envío al número real de peers activos.
Límite de propagación de tarjeta (card_hop_limit)
Parametro complementario que controla hasta qué distancia (en saltos) puede llegar una tarjeta compartida desde su origen. Cuando un peer anuncia su card_map via CMD_CARD_MAP, las entradas con hop > card_hop_limit se descartan directamente: no se almacenan, no se usan y no se reenvían a otros peers.
- 0 — sin límite (comportamiento por defecto). Se aceptan tarjetas hasta hop 10 (límite absoluto contra propagación anómala).
- 1 — solo tarjetas directas: hop 0 (propias) y hop 1 (un salto desde el origen).
- N — se aceptan tarjetas con hasta N saltos de distancia. Maximo configurable: 10.
Útil para operadores que quieren garantizar que sus tarjetas no llegan a redes a las que no conocen. A diferencia del campo por cuenta max_hops y reshare_hops (que controlan qué se envía a un peer concreto), card_hop_limit actua en recepcion: filtra lo que Candela acepta de cualquier peer.
Prioridad por latencia en todas las fuentes locales
Ademas de ordenar los peers P2P por score HLS, Candela aplica selección por latencia media a todas las fuentes locales que pueden servir un mismo CAID:
- Lectores NewCamd cliente: si hay varias líneas NewCamd conectadas con el mismo CAID:PROVID, se usa siempre la que tiene menor
avg_latency_mshistórico. Sin datos previos, el reader se trata como de alta latencia hasta acumular al menos una medición. - Lectores MGcamd cliente: mismo mecanismo. El reader más rápido históricamente recibe la ECM primero.
- Lectores hardware físicos: cuando hay varios lectores compatibles y MCRR esta desactivado, se ordenan por
avg_latency_msantes de intentarlos. Con MCRR activo se respeta la asignacion determinista por SRVID.
La latencia se mide con CLOCK_MONOTONIC en cada descifrado éxitoso y se actualiza con EMA (70 % histórico, 30 % muestra nueva). El resultado es que, tras las primeras ECMs, el reader más rápido para cada CAID se seleccióna automáticamente sin configuración adicional.
Config
| Campo | Default | Descripción |
|---|---|---|
ecm_multipath | 3 | 0 = todos los peers. 1 = modo clasico (un peer). N = top-N peers en paralelo. Sin límite superior. |
card_hop_limit | 0 | Hop máximo aceptado en card_map de peers. 0 = sin límite. 1 = solo directas. N = hasta N saltos. Maximo 10. |
Se configuran desde Mantenimiento → Transporte y Anti-DPI → AMPE - Multi-Path ECM.
🛡 TAR - Anti-DPI Suite (Traffic Analysis Resistance)
Motivación: los vectores DPI que CTC y CPM no resuelven
CTC oculta el contenido (framing TLS) y resuelve el bloqueo por perfil de protocolo desconocido. CPM entierra el patrón temporal de latido DVB (silencio/ráfaga a intervalos de 10-15s). Sin embargo, un ISP con capacidad de DPI estadístico avanzado dispone de cuatro vectores adicionales que estos módulos no cubren:
| Vector DPI | Descripción | Módulo TAR |
|---|---|---|
| Firma de tamaño de paquete | Los paquetes CMD_ECM_REQ (~150 bytes) y CMD_CW_RESP (~32 bytes) tienen tamaños características. El padding variable del protocolo base no llega a una distribución plana: el análisis estadístico sobre una muestra larga puede extraer los picos. | PSN |
| Patrón temporal de ECMs | El jitter básico (xorshift Poisson) aplana el espectro a corto plazo, pero no a largo: con suficiente tiempo de observación, un análisis de autocorrelación puede recuperar el periodo del criptoperíodo DVB (~10s). | ETJ |
| Ausencia de tráfico de fondo | El tráfico HTTPS real presenta ráfagas de descarga sostenidas. Un flujo Candela con solo chaff periódico y ECMs tiene una tasa de bits media muy baja e irregular - detectable por perfil de caudal. | CTF |
| Duración de sesión TCP | Las sesiones HTTPS duran segundos o minutos. Las conexiónes P2P de cardsharing duran días o semanas. Un DPI de metadatos identifica el servicio sin leer ningún byte, solo por la duración del flujo TCP. | TCR |
PSN - Packet Size Normalization
Los paquetes salientes se normalizan a uno de cinco buckets de tamaño fijo antes de envíarse: 128 · 256 · 512 · 1024 · 1400 bytes. Cualquier payload se redondea al bucket superior más cercano y se rellena hasta ese tamaño con bytes pseudoaleatorios cifrados. El receptor descarta el relleno tras el descifrado ChaCha20-Poly1305 usando la longitud real incluida en la cabecera del paquete Candela.
- Elimina la distribución estadística de tamaños que distingue ECMs de CWs de chaff.
- La distribución resultante es discreta y uniforme - idéntica a TLS con registros de Application Data de tamaño estándar.
- Overhead: 0 a ~180 bytes por paquete dependiendo del bucket (media ~90 bytes).
- Config:
enable_psn = 1(activo por defecto).
ETJ - ECM Timing Jitter
Introduce un retardo pseudoaleatorio adicional antes de reenvíar cada ECM upstream: entre 0 y etj_max_ms ms (default: 400ms), generado con xorshift32 de forma que la distribución en frecuencia sea plana. La autocorrelación del periodo ECM (~10s) no es detectable aunque el observador acumule horas de tráfico.
- No afecta la latencia percibida: el margen del criptoperíodo DVB (~500ms-1s antes del corte) absorbe el jitter sin impacto visible.
- Config:
enable_etj = 1,etj_max_ms(rango recomendado: 200-600ms).
CTF - Constant Traffic Floor
Mantiene un caudal mínimo constante de tráfico sintético hacia cada peer activo: ctf_floor_kbps kbps (default: 0 = desactivado). El relleno se emite como paquetes CMD_PADDING cifrados con ChaCha20-Poly1305+CTC, indistinguibles del tráfico real para cualquier observador externo. El resultado es un flujo con tasa de bits mínima garantizada similar a una descarga HTTPS de baja velocidad continua.
- Con CTF + CPM activos: tasa de bits mínima garantizada (CTF) y sin silencios > 3.5s (CPM). El perfil de caudal es el de una conexión HTTPS de streaming.
- Coste típico: 5-20 kbps por peer en routers domésticos; 50-100 kbps en VPS con pocos peers de alto tráfico.
- Config:
ctf_floor_kbps(0 = desactivado; rango útil: 5-200 kbps).
TCR - TCP Connection Rotation
Rota la sesión TCP de forma transparente y periódica. El intervalo se programa como [N, 4×N] horas donde N = tcp_rotation_h, usando jitter xorshift32 para evitar sincronización entre nodos que arrancaron simultáneamente. El ISP nunca observa una conexión P2P con duración superior a 4×N horas - dentro del rango normal de sesiones HTTPS largas (streaming, llamadas, videoconferencia).
- La reconexión TCR se marca internamente como planificada, por lo que el contador de reconexiónes del dashboard no se incrementa - no genera falsa alarma.
- Transparencia: el peer acepta la nueva conexión con el handshake CTC+ECDH X25519 habitual. La caché CW y el buffer del receptor absorben los ~150-300ms de reconexión sin corte de imagen.
- Ejemplo:
tcp_rotation_h = 6→ rotación entre las 6h y las 24h. Ninguna sesión TCP dura más de un día. - Config:
tcp_rotation_h(0 = desactivado; rango: 2-24h).
SCC - Simultaneous Channel Cap (R38)
Limita el número de SRVIDs (canales) distintos activos simultáneamente en el lector de tarjeta físico. Cuando el contador de canales activos alcanza scc_max_channels, los ECMs de canales nuevos se redirigen a P2P en lugar de ir a la tarjeta local. Un SRVID se considera activo mientras haya ECMs periódicos; expira tras scc_window_s segundos sin actividad.
- Para la CA de la operadora: el perfil de uso de la tarjeta no supera el de un suscriptor multi-room estándar.
- Transparente para el cliente: si hay P2P disponible para el canal bloqueado, el servicio continúa sin interrupción.
- Config:
scc_max_channels(0 = desactivado),scc_window_s(default 30 s).
ETS - ECM Temporal Spreading (R38)
Cuando múltiples canales nuevos envían su primera ECM al lector en ráfaga simultánea (dentro de una ventana de 500 ms), cada ECM recibe un retardo pseudoaleatorio independiente de [1, ets_max_spread_ms] ms antes de llegar a la tarjeta. Durante el retardo, la ECM queda encolada con prioridad de reintento local (mecanismo HW_READER_ALL_BUSY); el watchdog la reintenta cada ~250 ms hasta que el spreading expira.
- El spreading solo aplica al primer ECM de cada SRVID nuevo en ráfaga. Las ECMs de refresco de canales ya activos (SRVID conocido en la tabla SCC) pasan sin retardo.
- Detección de ráfaga: si un solo canal inicia sin otros concurrentes en 500 ms, no hay delay - no penaliza el cambio de canal individual.
- Config:
enable_ets(1 = activo por defecto),ets_max_spread_ms(default 2000 ms).
ECM Coalescing Agresivo (R38)
Algunos sistemas CA (especialmente Viaccess y variantes Nagra) generan ECMs con payload ligeramente distinto en cada criptoperíodo aunque la CW resultante sea la misma: añaden un nonce interno o timestamp propio. El caché por hash de ECM exacto no detecta estos duplicados y el lector hardware recibe peticiónes redundantes. El Coalescing resuelve esto deduplicando por CAID+PROVID+SRVID dentro de una ventana temporal.
- Si el lector resolvió una ECM para el mismo canal en los últimos
ecm_coalesce_window_msms, se reutiliza la CW sin tocar el hardware. - Complementario al caché CW existente: el caché actúa sobre el hash exacto de ECM; el Coalescing actúa sobre el canal independientemente del payload.
- La ventana máxima (9000 ms) es inferior al criptoperíodo DVB estándar (10 s), por lo que no hay riesgo de servir una CW caducada.
- Config:
ecm_coalesce_window_ms(0 = desactivado; rango útil: 4000-7000 ms).
ECM Relay - Anti-correlación de tráfico (R39)
Enruta ECMs hacia el destino a través de un nodo P2P intermediario (relay), de forma que un observador externo (ISP, sonda de red) que analice metadatos de conexión TCP no puede correlacionar directamente quién originó la petición con quién la resolvió. El relay no tiene acceso al contenido, que viaja siempre cifrado ChaCha20-Poly1305.
- Flujo: origen envía la ECM al relay (CMD_ECM_RELAY); el relay la reenvía al destino (CMD_ECM_REQ); el destino resuelve la CW y la devuelve al relay; el relay la reenvía al origen (CMD_ECM_RELAY_RESP). El relay nunca tiene acceso al contenido, siempre cifrado.
- Compatible con AMPE: cada path paralelo usa un relay distinto; si no hay relay disponible para un path concreto, ese path cae a directo sin afectar a los otros.
- La tabla interna de seguimiento soporta hasta 64 peticiónes simultáneas con timeout de 10 s por entrada.
- Config:
enable_ecm_relay(0 = desactivado por defecto).
MCRR - Multi-Card Round-Robin (R39)
Distribuye los ECMs entre múltiples lectores de tarjeta físicos presentes en el mismo nodo. El lector asignado se calcula como SRVID % num_readers, lo que hace la asignación determinista (el mismo canal siempre va al mismo lector) y compatible con la caché CW. Si el lector asignado está al límite de paralelismo configurado, la iteración circular avanza al siguiente lector compatible.
- El lector virtual MOSC siempre se intenta primero, antes de aplicar MCRR. No entra en la rotación.
- Pre-scan de lectores compatibles: solo participan en la rotacion los lectores en estado READY, habilitados, con CAID y PROVID coincidentes. El lector virtual MOSC se excluye de la rotacion y siempre se intenta primero.
- Si no hay lectores compatibles el watchdog deriva la petición a P2P automáticamente.
- Config:
enable_mcrr(0 = desactivado por defecto).
Cobertura total acumulada
Config
| Campo | Default | Descripción |
|---|---|---|
| enable_psn | 1 | Normalización de tamaño de paquetes a buckets fijos (128/256/512/1024/1400 bytes). |
| enable_etj | 1 | Jitter temporal aleatorio en reenvío de ECMs upstream. |
| etj_max_ms | 400 | Jitter máximo en ms para ETJ. Rango útil: 50-1000ms. |
| ctf_floor_kbps | 0 | Caudal mínimo de tráfico sintético por peer en kbps. 0 = desactivado. |
| tcp_rotation_h | 0 | Horas base de rotación TCP. Rotación ocurre en [N, 4×N] horas. 0 = desactivado. Rango: 2-24h. |
| Operator Stealth - R38 | ||
| scc_max_channels | 0 | Máx. SRVIDs activos simultáneos en lector local. 0 = desactivado. Rango: 0-32. |
| scc_window_s | 30 | Segundos sin ECM para expirar un SRVID de la tabla SCC. Rango: 5-300 s. |
| enable_ets | 1 | Activa ECM Temporal Spreading (distribución temporal de ECMs en ráfaga). |
| ets_max_spread_ms | 2000 | Ventana de spreading máximo para ECMs en ráfaga. 0 = sin spreading. Rango: 0-8000 ms. |
| ECM Coalescing - R38 | ||
| ecm_coalesce_window_ms | 0 | Ventana de deduplicación por CAID+PROVID+SRVID en ms. 0 = desactivado. Rango: 0-9000 ms. Valor recomendado: 5000 ms. |
| TAR R39 - ECM Relay + MCRR | ||
| enable_ecm_relay | 0 | Activa ECM Relay (CMD 0x17/0x18). Rompe correlación IP ante observadores externos. Compatible con AMPE. |
| enable_mcrr | 0 | Activa Multi-Card Round-Robin. Distribuye ECMs entre lectores físicos por SRVID % num_readers. |
Todos los parámetros se configuran desde WebIf → Mantenimiento → Transporte y Anti-DPI.
Control avanzado de caché, CW Cycle Check y DoubleCheck por CAID
Nuevos parámetros de configuración para control granular de memoria de caché CW/ECM, Cycle Check avanzado y DoubleCheck selectivo por CAID.
Control de memoria de caché
| Campo | Default | Descripción |
|---|---|---|
| cw_cache_memory | 0 | Límite RAM para caché CW en MB. 0 = sin límite. |
| ecm_cache_size | 0 | Máx. entradas en caché ECM. 0 = sin límite. |
| ecm_cache_memory | 0 | Límite RAM para caché ECM en MB. 0 = sin límite. |
CW Cycle Check avanzado
Los parámetros avanzados se muestran en el WebIF solo cuando cw_cycle_check = 1.
| Campo | Default | Descripción |
|---|---|---|
| cwcycle_check_caid | "" | CAIDs donde aplicar Cycle Check. Vacío = todos los CAIDs. Formato: 0100,0500,1810 |
| cwcycle_maxlist | 4000 | Máximo de entradas en la lista de ciclos. |
| cwcycle_keeptime | 25 | Retención de ciclos detectados en segundos. |
| cwcycle_sensitive | 2 | Sensibilidad: 1 = bajo, 2 = medio, 3 = alto. |
| cwcycle_usecwcfromce | 1 | Usar CWs del CacheExchanger para alimentar la detección de ciclos. |
DoubleCheck por CAID
| Campo | Default | Descripción |
|---|---|---|
| double_check_caid | "" | Aplica DoubleCheck solo a estos CAIDs. Vacío = todos. El campo aparece en el WebIF solo cuando enable_doublecheck = 1. |
WebIF
- Inputs numéricos para
cw_cache_memory,ecm_cache_size,ecm_cache_memoryen la tarjeta "Control de CW". - Sección avanzada de Cycle Check con
v-if="cwCycleCheck": lista CAID, maxlist, keeptime, selector de sensibilidad (1/2/3), toggle usecwcfromce. - Input
double_check_caidconv-if="configObj.enable_doublecheck". - Traducciones en 6 idiomas: ES, EN, DE, FR, IT, PT.
Mejoras de seguridad incluidas en R35
| Fix | Archivo | Descripción |
|---|---|---|
| Race condition tokens de sesión | webif.c | Generación en buffers locales antes del mutex. |
sprintf → snprintf | webif.c, cache.c | Longitud explícita en serialización de hashes. |
strcpy → snprintf | reader_hw.c | Buffer defensivo en rom_revision. |
explicit_bzero antes de free | webif.c | Password no queda en heap liberado. |
| SNI independiente del NodeID | ctc.c | Pool de 6 CDNs reales + prefijo RAND_bytes. |
ALPN h2+http/1.1 | ctc.c | Extensión presente en todos los ClientHello. |
| Cipher suites randomizados | ctc.c | AES-128 ó CHACHA20 primero (50/50 por sesión). |
| Jitter pre-ClientHello 10–100ms | ctc.c | Simula latencia humana pre-TLS. |
| Tommy O(1) en srvid.c | srvid.c | Lookup de canal O(1) vs O(65536) anterior. |