Configuración de Kamailio para WebRTC: Guía Completa de Implementación

WebRTC (Web Real-Time Communication) representa una auténtica revolución en las comunicaciones en tiempo real a través de navegadores web. Esta tecnología permite la comunicación directa entre navegadores sin necesidad de plugins o software adicional, convirtiéndose en un estándar fundamental para aplicaciones VoIP modernas.

En este artículo profundizaremos en la configuración de Kamailio para procesar correctamente señalización SIP sobre WebSocket, permitiendo establecer llamadas entre diferentes tipos de endpoints: UDP tradicional, TLS y WebSocket Secure (WSS).

¿Qué es WebRTC?

WebRTC proporciona tres APIs principales en JavaScript que permiten a los desarrolladores crear aplicaciones de comunicación interactivas:

APIs Fundamentales

  1. getUserMedia: Solicita acceso a dispositivos de audio/vídeo presentes en computadores, tablets y smartphones
  2. RTCPeerConnection: Establece un flujo de media directo (peer-to-peer) entre los interlocutores
  3. RTCDataChannel: Permite el intercambio de datos fuera del flujo de media (mensajes de texto, fotos, archivos)

Protocolos y Codecs

El flujo de media en WebRTC utiliza:

  • SRTP sobre DTLS: Protocolo cifrado basado en TLS específicamente diseñado para datagramas UDP
  • Codecs de audio: alaw, ulaw y Opus
  • Codecs de vídeo: VP8 y H.264 (según RFC7742)
  • ICE (RFC8445): Protocolo para atravesar NAT con 99% de efectividad

Señalización Flexible

WebRTC no impone un protocolo de señalización específico. Puede utilizarse cualquier protocolo, siendo SIP y XMPP los más populares. La RFC7118 (enero 2014) estandariza el uso de WebSocket como transporte para SIP, permitiendo la integración con infraestructuras VoIP existentes.

La configuración que implementaremos permitirá los siguientes escenarios de llamadas:

UDP  ←→ UDP
UDP  ←→ WSS
WSS  ←→ UDP
WSS  ←→ WSS

Opcionalmente, también se puede configurar para:

TLS  ←→ TLS
TLS  ←→ WSS
WSS  ←→ TLS
WSS  ←→ WSS

La construcción del enrutamiento se basa en principios fundamentales de:

  1. Detección de protocolo: Identificación correcta del protocolo de transporte (UDP, TLS, WSS)
  2. Bridge/Puente de protocolos: Conversión transparente entre diferentes transportes
  3. Gestión de NAT: Manejo específico para clientes WebRTC tras NAT
  4. Manipulación de media: Configuración dinámica de RTPEngine según el escenario
route[PUENTE] {
    if (!has_totag()) {
        if ($proto =~ "wss" && !($ru =~ "transport=wss")) {
            xlog("L_INFO","Puente WSS-UDP branch=$bf proto=$proto");
            setbflag(FLB_PUENTE);
        } else if (!($proto =~ "wss") && $ru =~ "transport=wss") {
            xlog("L_INFO","Puente UDP-WSS branch=$bf proto=$proto");
            setbflag(FLB_PUENTE);
        }
    }
}

Este bloque utiliza:

  • Verificación de has_totag() para detectar diálogos iniciales
  • Pattern matching con expresiones regulares para detectar protocolo de origen y destino
  • Branch flags (bflags) para marcar transacciones que requieren conversión
  • Logging detallado para troubleshooting

Ventaja: Permite decisiones de enrutamiento contextuales sin requerir verificaciones repetidas en cada punto del flujo.

#!ifdef WITH_WEBSOCKET
    if (nat_uac_test(64)) {
        if (is_method("REGISTER")) {
            fix_nated_register();
        } else if (!add_contact_alias()) {
            xlog("L_ERR", "Error aliasing contact <$ct>\n");
            sl_send_reply("400", "Bad Request");
            exit;
        }
    }
#!endif

Implementación que:

  • Usa nat_uac_test(64) específicamente para detectar WebSocket
  • Aplica correcciones diferenciadas según el método SIP
  • Maneja errores apropiadamente con respuestas SIP estándar
  • Utiliza contact aliasing para tracking de conexiones WebSocket

Punto clave: El flag 64 es específico para WebSocket, diferenciándolo de otras detecciones NAT tradicionales.

Este es el corazón de la solución y merece un análisis detallado:

route[RTPENGINE] {
    if(!is_method("INVITE")) return;
    
    $xavp(r=>$T_branch_idx) = "replace-origin replace-session-connection";
    
    if(nat_uac_test("8")) {
        $xavp(r=>$T_branch_idx) = $xavp(r=>$T_branch_idx) + " trust-address";
    }
    
    # Gestión de via-branch para tracking
    if (is_request()) {
        if (!has_totag()) {
            if (!t_is_failure_route()) {
                $avp(extra_id) = @via[1].branch + $T_branch_idx;
                $xavp(r=>$T_branch_idx) = $xavp(r=>$T_branch_idx) + " via-branch=extra";
            }
        }
    }
    
    if (is_reply()) {
        $avp(extra_id) = @via[2].branch + $T_branch_idx;
        $xavp(r=>$T_branch_idx) = $xavp(r=>$T_branch_idx) + " via-branch=extra";
    }
    
    # Configuración específica de conversión
    if (isbflagset(FLB_PUENTE)) {
        if ($proto =~ "wss") {
            # De WSS a SIP (UDP/TCP)
            $xavp(r=>$T_branch_idx) = $xavp(r=>$T_branch_idx) + 
                " rtcp-mux-demux DTLS=off SDES-off ICE=remove RTP/AVP";
        } else {
            # De SIP a WSS
            $xavp(r=>$T_branch_idx) = $xavp(r=>$T_branch_idx) + 
                " rtcp-mux-offer generate-mid DTLS=passive SDES-off ICE=force RTP/SAVPF";
        }
    } else {
        if ($proto =~ "ws") {
            # WSS a WSS
            $xavp(r=>$T_branch_idx) = $xavp(r=>$T_branch_idx) + 
                " generate-mid DTLS=passive SDES-off ICE=force";
        }
    }
    
    xlog("L_INFO", "NATMANAGE branch_id:$T_branch_idx ruri: $ru, metodo:$rm, 
        CseQ:$cs status:$rs, extra_id: $avp(extra_id), 
        rtpengine_manage: $xavp(r=>$T_branch_idx)\n");
    
    rtpengine_manage($xavp(r=>$T_branch_idx));
}
a) Uso de XAVP para Branch-Level Configuration
  • Cada rama de transacción ($T_branch_idx) tiene su propia configuración
  • Ventaja: Permite forking con diferentes configuraciones RTPEngine por branch
  • Caso de uso: Usuario registrado en múltiples dispositivos (UDP + WSS simultáneamente)
b) Parámetros de Conversión WSS→UDP
rtcp-mux-demux DTLS=off SDES-off ICE=remove RTP/AVP
Parámetro Función Justificación
rtcp-mux-demux Desmultiplexa RTP y RTCP WebRTC usa un solo puerto, SIP tradicional espera puertos separados
DTLS=off Desactiva DTLS El endpoint UDP no soporta cifrado DTLS
SDES-off Desactiva SDES No se usa SDES para key exchange en esta dirección
ICE=remove Elimina candidates ICE El endpoint UDP no procesa ICE
RTP/AVP Perfil RTP básico Sin cifrado, compatible con dispositivos legacy
c) Parámetros de Conversión UDP→WSS
rtcp-mux-offer generate-mid DTLS=passive SDES-off ICE=force RTP/SAVPF
Parámetro Función Justificación
rtcp-mux-offer Ofrece multiplexado RTP/RTCP Requerido por WebRTC
generate-mid Genera media identification Necesario para BUNDLE
DTLS=passive RTPEngine actúa como servidor DTLS Espera handshake del cliente
SDES-off Desactiva SDES WebRTC usa DTLS-SRTP
ICE=force Fuerza generación de candidates Obligatorio para WebRTC
RTP/SAVPF Secure Audio/Video Profile with Feedback Estándar WebRTC con cifrado
d) Via-Branch Tracking
$avp(extra_id) = @via[1].branch + $T_branch_idx;

Propósito: Crear identificadores únicos para sesiones RTPEngine que persisten a través de re-INVITEs y actualizaciones. Crucial para:

  • Call hold/resume
  • Codec renegotiation
  • Session updates

Configuración Paso a Paso

1. Prerequisitos

Los certificados TLS/DTLS deben estar creados previamente (reutilizados de configuración TLS de Kamailio).

2. Activación de Módulos

Agregar en kamailio.cfg:

#!define WITH_WEBSOCKET

Cargar módulos necesarios:

#!ifdef WITH_WEBSOCKET
    loadmodule "xhttp.so"
    loadmodule "websocket.so"
#!endif

Módulos y sus funciones:

  • xhttp: Servidor web básico para manejar peticiones HTTP
  • websocket: Servidor WebSocket para señalización SIP

3. Configuración de Listeners

listen=tls:IP_PUBLICA:8443

Nota: Se usa puerto 8443 por convención (puede personalizarse).

4. Parámetros Globales TCP

#!ifdef WITH_WEBSOCKET
    tcp_accept_no_cl=yes
    http_reply_parse=yes
#!endif

Explicación:

  • tcp_accept_no_cl=yes: Acepta requests sin header Content-Length
  • http_reply_parse=yes: Permite parsear respuestas HTTP (necesario para WebSocket handshake)

5. Event Routes para WebSocket

Gestión de Conexiones (event_route[xhttp:request])

event_route[xhttp:request] {
    set_reply_close();
    set_reply_no_connect();
    
    # Validar puerto
    if ($Rp != 8443) {
        xlog("L_WARN", "HTTP request received on $Rp\n");
        xhttp_reply("403", "Forbidden", "", "");
        exit;
    }
    
    xlog("L_DBG", "HTTP Request Received $hu\n");
    
    # Validar WebSocket upgrade
    if ($hdr(Upgrade)=~"websocket"
            && $hdr(Connection)=~"Upgrade"
            && $rm=~"GET") {
        
        # Validar Host
        if ($hdr(Host) == $null || !is_myself("sip:" + $hdr(Host))) {
            xlog("L_WARN", "Bad host $hdr(Host)\n");
            xhttp_reply("403", "Forbidden", "", "");
            exit;
        }
        
        # Ejecutar handshake
        if (ws_handle_handshake()) {
            exit;
        }
    }
    
    xhttp_reply("404", "Not found", "", "");
}

Análisis:

  • Implementa security best practices
  • Valida upgrade headers según RFC6455
  • Verifica que el Host es válido

Logging de Cierre (event_route[websocket:closed])

event_route[websocket:closed] {
    xlog("L_INFO", "WebSocket connection with id $ws_conid from $si:$sp has closed\n");
}

Utilidad: Debugging y monitoreo de conexiones activas.

6. Gestión de Respuestas

#!ifdef WITH_WEBSOCKET
onreply_route {
    if (nat_uac_test(64)) {
        add_contact_alias();
    }
}
#!endif

Función: Añade alias de contacto en respuestas para mantener routing correcto.

7. Firewall (IPTables)

-A INPUT -p tcp -m state --state NEW -m tcp --dport 8443 -j ACCEPT

Seguridad Avanzada: CORS (Cross-Origin Resource Sharing) y Origin Validation

Para restringir acceso solo a dominios autorizados:

if ($hdr(Origin) != "https://campus.miodominio.org") {
    xlog("L_WARN", "Unauthorised client $hdr(Origin)\n");
    xhttp_reply("403", "Forbidden", "", "");
    exit;
}

Consideraciones:

  • Implementa CORS a nivel SIP
  • Previene uso no autorizado del servidor
  • Lista blanca de dominios permitidos

Testing y Validación

1. Verificación de Configuración

kamailio -c /etc/kamailio/kamailio.cfg

Salida esperada:

Listening on
     udp: IP_PUBLICA [IP_PUBLICA]:5060
     udp: IP_PRIVADA [IP_PRIVADA]:5060
     tls: IP_PUBLICA [IP_PUBLICA]:8443
Aliases:
config file ok, exiting...

2. Creación de Usuario WebRTC

kamctl add 1003@sip1.miodominio.org PassWord

3. Cliente WebRTC Recomendado

Sugiero usar Browser-Phone, un softphone WebRTC amigable.

Configuración típica:

  • WebSocket URI: wss://sip1.miodominio.org:8443
  • Usuario: 1003
  • Password: PassWord
  • Display Name: Usuario WebRTC

4. Escenarios de Prueba

Origen Destino Resultado Esperado
WSS (1003) UDP (1001) Conversión WSS→UDP, audio bidireccional
UDP (1001) WSS (1003) Conversión UDP→WSS, video si disponible
WSS (1003) WSS (1004) Comunicación nativa WebRTC, máxima calidad
UDP (1001) UDP (1002) Sin conversión, routing tradicional

5. Troubleshooting

Llamadas no se establecen

Verificar:

  1. RTPEngine está corriendo: systemctl status rtpengine
  2. Puertos UDP abiertos: 10000-20000/udp para RTP
  3. Logs de Kamailio: kamlog | grep -i error
  4. SDP en INVITE: sngrep para captura de paquetes

Audio unidireccional

Causas comunes:

  • Configuración incorrecta de rtcp-mux-demux
  • ICE candidates no alcanzan el endpoint
  • Firewall bloqueando RTP

Solución:

# Verificar flags de RTPEngine
kamcmd rtpengine.show all

Configuraciones Alternativas

Solo TLS + WebRTC

Para entornos que requieren cifrado end-to-end:

TLS ←→ TLS
TLS ←→ WSS
WSS ←→ TLS
WSS ←→ WSS

Modificación en route[PUENTE]:

route[PUENTE] {
    if (!has_totag()) {
        # Detectar cualquier combinación de protocolos seguros
        if (($proto =~ "wss" || $proto =~ "tls") && 
            !($ru =~ "transport=wss" || $ru =~ "transport=TLS")) {
            xlog("L_INFO","Puente seguro $proto a estándar");
            setbflag(FLB_PUENTE);
        } else if (!($proto =~ "wss" || $proto =~ "tls") && 
                   ($ru =~ "transport=wss" || $ru =~ "transport=TLS")) {
            xlog("L_INFO","Puente estándar a seguro");
            setbflag(FLB_PUENTE);
        }
    }
}

Monitoreo y Métricas

Comandos Útiles

# Ver conexiones WebSocket activas
kamcmd ws.dump

# Estadísticas de RTPEngine
kamcmd rtpengine.show all

# Dialogos activos
kamcmd dlg.list

Métricas Clave

  1. Conexiones WebSocket activas: Debe correlacionar con registros activos
  2. Sesiones RTPEngine: Una por llamada activa
  3. Branch failures: Idealmente < 1% de llamadas totales
  4. Latencia de handshake: < 500ms para buena experiencia

Próximos Pasos

  1. Implementar Rate Limiting para prevenir ataques
  2. Configurar Load Balancing de RTPEngine
  3. Integrar con sistema de Billing
  4. Implementar QoS monitoring

Recursos Adicionales

Tags: #Kamailio #WebRTC #VoIP #SIP #RTPEngine #RealTimeCommunications #TelecomEngineering

 

Vota el Articulo: 

Sin votos (todavía)
Evalúa la calidad del articulo
Suscribirse a Comentarios de "Configuración de Kamailio para WebRTC: Guía Completa de Implementación" Suscribirse a VozToVoice - Todos los comentarios