En vista de la ensalada de soluciones existentes para abordar el tema de SIP y NAT me propongo tratar de explicar algunas de ellas. Igualmente trataré de desmentir algunas hipótesis que se escuchan de vez en cuando.
Problema del NAT en SIP y RTP
No voy a excederme relatando los problemas que ocasiona el NAT para las comunicaciones SIP. Supongamos un cliente SIP detrás de NAT que trata de comunicarse con otro fuera de su NAT, ambos usuarios usan el mismo proxy SIP:
Usuario SIP origen:- SIP URI: ibc@mydomain.org
- IP privada: 192.168.1.33
- IP pública del router NAT: 81.35.221.20
- SIP URI: destino@mydomain.org
- IP pública: 88.95.20.130
- Dominio: mydomain.org
- IP pública: 60.55.201.100
El mensaje SIP INVITE que enviaría mi usuario sería así:
INVITE sip:destino@mydomain.org SIP/2.0
Via: SIP/2.0/UDP 192.168.1.33:5060;rport;branch=z9hG4bKjyofoqmp
Max-Forwards: 70
To: <sip:destino@mydomain.org>
From: "Iñaki" <sip:ibc@mydomain.org>;tag=nrrrx
Call-ID: xetazdjyktlpsfo@192.168.1.33
CSeq: 800 INVITE
Contact: <sip:ibc@192.168.1.33:5060>
Content-Type: application/sdp
Allow: INVITE,ACK,BYE,CANCEL,OPTIONS,PRACK,REFER,NOTIFY,SUBSCRIBE,INFO,MESSAGE
Supported: replaces,norefersub,100rel
User-Agent: Twinkle/1.1
Content-Length: 312
v=0
o=ibc 1090098764 894503441 IN IP4 192.168.1.33
s=-
c=IN IP4 192.168.1.33
t=0 0
m=audio 8000 RTP/AVP 98 97 8 0 3 101
a=rtpmap:98 speex/16000
a=rtpmap:97 speex/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:3 GSM/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=ptime:20
a=zrtp
En rojo señalo los problemas ocasionados por estar tras NAT:
- La cabecera Via: SIP/2.0/UDP 192.168.1.33:5060 no supone problema pues nuestro proxy SIP añadirá su propio "Via" indicando al llamado por dónde debe rutar las respuestas al INVITE.
- La cabecera Contact: <sip:ibc@192.168.1.33:5060> indicará al receptor dónde enviar los mensajes de nuevas transacciones, es decir, la dirección y puerto a la que el receptor deberá enviar el BYE si quiere colgar, el INVITE si quiere hacer un re-INVITE (p.ej: poner en espera), el REFER si quiere transferir la llamada. Todos estos mensajes pertenecerían al mismo diálogo o comunicación SIP (diálogo = conjunto de transacciones que comparten mismo "Caller-Id" y tags en "To" y "From"), pero serían nuevas transacciones (transacción = mensaje SIP + respuestas) por lo que no se rutarían por la cabecera "Via". Obviamente se trata de una IP privada no direccionable desde fuera de mi red privada.
- La cabecera SDP c=IN IP4 192.168.1.33 indicará al receptor dónde enviar el tráfico de audio RTP. Lo mismo, es una IP privada no direccionable.
- La cacebera SDP m=audio 8000 indicará al receptor a qué puerto enviar el tráfico de audio RTP. Ese puerto es irrelevante en cuanto a que la IP es privada no direccionable.
Estos problemas imposibilitan la comunicación SIP y RTP.
Soluciones NAT de lado cliente
En esta sección comento algunas soluciones para el NAT que existen en el lado del cliente, es decir, o bien en su dispositivo SIP o bien en su router/firewall NAT.
STUN (Simple Traversal of UDP through NAT)
STUN, ese gran desconocido. Sencillamente lo que hace un dispositivo que usa STUN es, antes de registrarse y/o hacer llamadas, se pone en contacto con un servidor STUN que le hayamos indicado en la configuración (ej: stun.ekiga.net) y se entera de si está tras NAT y tras qué tipo de NAT. Me explico mejor:
- Arrancamos nuestro dispositivo SIP. Este tiene configurado usar STUN contra un servidor STUN.
- En su configuración SIP y RTP tiene un puerto(s) asignado, supongamos SIP 5060 y RTP 8000.
- Inicia el test de STUN contra el servidor de STUN. Dicho test hace una serie de consultas que, más o menos, serían:
- Hola servidor STUN, ¿con qué IP y puerto me ves? Entonces el dispositivo se entera de si está tras NAT o no. En caso afirmativo continúa el test:
- Te envío un paquete desde mi puerto local 5060 y luego otro desde el 8000, ¿tú qué IP y puertos mapeados en mi router NAT recibes? Esto le permite al dispositivo conocer con qué IP y puertos saldría vía IP pública desde su router NAT (hay que tener en cuenta que un router NAT puede manejar más de una IP pública).
- ¿Y si te hago la misma consulta pero a tu segunda IP pública? ¿ves la misma IP y puertos? Esto es crucial y sirve para detectar el NAT simétrico, el único que impide el funcionamiento de STUN. Si el servidor STUN ve la misma IP y puertos origen entonces el dispositivo ya sabe qué IP pública y puertos debe indicar en sus mensajes SIP corrigiendo los que aparecían en rojo.
Supongamos que el puerto SIP 5060 se mapea en el router NAT al 15060 y el RTP 8000 al 1800, entonces el dispositivo SIP indicaría esos valores en su mensaje INVITE en vez de los indicados en rojo. Con esto sencillamente se consigue que nuestro dispositivo SIP aparente tener IP pública.
Nota importante: El test se parece bien poco a como lo he descrito además de tener en cuenta otras consideraciones como bloqueos de puertos y demás. Para verlo en detalle referirse a RFC 3489 sección 10.2.
Limitaciones de STUN
- STUN no funciona con NAT simétrico (bastante implementado en routers NAT típicos ofrecidos por las operadoras para ADSL). Esto es debido a que este tipo de NAT no garantiza que si contactas con distintas IP's externas éstas te vean con el mismo puerto público. Es decir, el test de STUN no serviría puesto que no sabes con qué puertos te verá el destino SIP.
- STUN necesita mantener el keepalive de SIP para que el router NAT no cierre la entrada de nuevos mensajes SIP transcurrido un cierto tiempo (p.ej: 20 segundos). Esto no es problema puesto que el propio cliente podría enviar mensajes SIP periódicos al destino (como un OPTIONS).
- STUN sólo sirve para UDP y no para TCP. Esto es debido a la forma en la que un router NAT detecta las conexiones establecidas para permitir nuevo tráfico entrante hacia la LAN. En UDP se considera "misma comunicación" si anteriormente un paquete UDP ha salido en sentido contrario hacia la IP y puerto público desde el que se reciben ahora nuevos paquetes UDP. Pero en TCP (protocolo orientado a conexión) el router/firewall NAT sólo considera una conexión TCP establecida si se ha seguido el protocolo para ello existente en el propio TCP, es decir: SYN, SYN/ACK y ACK.
La mágia del STUN
Supongamos dos dispositivos SIP tras NAT diferentes configurados contra un servidor SIP con IP pública. Ambos usan STUN.
Para los mensajes SIP no habría problema ya que se comunican sólo con el servidor SIP (si dicho proxy SIP permanece en el "callpath" añadiendo cabeceras "Record-Route") y permiten la entrada de mensajes manteniendo el keepalive. Es decir, podría funcionar tanto SIP UDP como SIP TCP.
Para el RTP se hace "magía". Un usuario llama al otro y en el establecimiento de llamada SIP ambos se indican entre sí sus IP públicas y puertos RTP (averiguados con STUN). Supongamos que el llamante envía el tráfico RTP un poco antes que el llamado. Esos primeros paquetes no atravesarán el router NAT del destino pues su router NAT no lo asocia a ninguna "conexión" UDP existente. Pero al de un rato el destino empieza a enviar tráfico RTP al puerto público del llamante. En ese momento el router del llamado permitirá la entrada del tráfico UDP que al principio impedía. Es, bajo mi punto de vista, toda una "trampa" al NAT y al sistema de detección de conexiones UDP en los firewalls. XD
Referencias de STUN
- RFC 3489 - STUN - Simple Traversal of User Datagram Protocol (UDP) Through Network Address Translators (NATs)
- STUN en la Wikipedia
Nota: STUN se considera solución de lado cliente aunque la realidad es que requiere de un servidor STUN en la red pública. Como dicho servidor no debe soportar demasiada carga y además existen un gran número de ellos disponibles al público no se considera solución de lado servidor.
TURN (Traversal Using Relay NAT)
Todavía más desconocido, y personalmente desconozco en qué grado se usa. TURN sirve para complementar los casos donde STUN no sirve (NAT simétrico y TCP), pero con el gran coste añadido de requerir de un servidor TURN por donde se enviará el tráfico.
Es decir, un servidor STUN sólo sirve para una consulta inicial de los clientes SIP, nada más, pero un servidor TURN se usa para enviar a través suyo el tráfico final. Obviamente en términos de RTP el uso de TURN debe ser la última opción a considerar.
Referencias de TURN
Nota: Puesto que el servidor TURN debe reunir unos requisitos de ancho de banda decentes, la opción de TURN debe considerarse como una solución de lado cliente y servidor.
ICE (Interactive Connectivity Establishment)
ICE no es en realidad un nuevo protocolo, sino una metodología que permite a los clientes investigar qué solución de lado cliente (por ejemplo STUN ó TURN) es la más adecuada según el escenario.
Referencias de ICE
ALG (Application Layer Gateway)
AGL es un sistema implementado en el router/firewall que examina los paquetes SIP que lo atraviesan y modifican las IP's y puertos para adecuarlos a su situación de NAT. Es, digamos, una solución transparente para el cliente. No obstante, por implementarse en su red local se considera solución de lado cliente.
Problemas con ALG
Al parecer muchas implementaciones ALG para SIP que vienen en los routers ADSL son nefastas y reescriben los puertos con valores subrealistas (fuera del rango de 2^16), lo que impide la transmisión del audio la mayoría de ocasiones.
Por ejemplo, en los routers Zyxel de la familia P660 es necesario desactivar los ALG de SIP vía telnet:
ip nat service sip active 0
Referencias de ALG
- IP Network Address Translator (NAT) Terminology and Considerations
- ALG en la Wikipedia
- Sitsotd: Solución SIP para Iptables
Redirección de puertos
La solución que nos queda por comentar sería la apertura y redirección de puertos para SIP y RTP en el router hacia nuestro dispositivo SIP de la LAN. Obviamente esta solución es completamente inaceptable si disponemos de un cierto número de dispositivos SIP puesto que habría que poner un puerto SIP y RTP diferente en cada uno y hacer las consiguientes redirecciones.
Soluciones NAT de lado servidor
En esta sección comento algunas soluciones para el NAT que existen en el lado del servidor, lo que conlleva a la total transparencia desde el punto de vista del cliente. En este caso será el servidor/proxy SIP el que tome medidas.
Proxy RTP
Un proxy RTP sirve como "pasarela" del tráfico RTP, de tal forma que el llamante y el llamado envían su tráfico RTP a través de él. Dicho proxy RTP es manejado desde un servidor SIP y debe disponer de IP pública para que sea accesibe a los usuarios.
Supongamos que un usuario tras NAT llama a través de su proxy SIP a un usuario SIP con IP pública:
- Un usuario tras NAT y sin ninguna solución de lado cliente hace una llamada a través de su proxy SIP.
- El proxy detecta que el INVITE proviene de una IP privada (mirando las cabeceras antes puestas en rojo) así que modifica las IP's y puertos del contacto SIP reemplazándolos por los valores de la IP y puertos públicos del router.
- Además reescribe la IP y puerto del SDP poniendo la IP del proxy RTP y un puerto que en una consulta previa dicho proxy RTP le haya ofrecido.
- Entonces se ruta el INVITE al destino, el cuál verá como punto de contacto SIP la IP pública del NAT llamante y como contacto RTP la IP pública del proxy RTP.
Así pues la comunicación SIP pasa por el proxy SIP (como debe ser) mientras que el tráfico de audio pasa por el proxy RTP que se encarga de puentear los flujos RTP de llamante y llamado.
Obsérvese también, que si el proxy SIP ha añadido cabeceras "Record-Route" para permanecer toda la llamada en el path, y como el proxy SIP ha puesto la IP pública NAT del llamante en la cabecera "Contact" del INVITE que luego ha rutado al llamado, entonces si el llamado cuelga la llamada enviará algo como:
BYE sip:ibc@81.35.221.20:15060 SIP/2.0Así que el proxy SIP rutará ese mensaje a la IP pública del llamante. Si esta cabecera no se hubiese corregido entonces sería:
BYE sip:ibc@192.168.1.33:5060 SIP/2.0Lo que provocaría que el proxy SIP no podría rutarla ya que intentaría rutarla a una IP privada.
Otras consideraciones
También hay que tener en cuenta el caso en el que el llamado esté tras NAT. En ese caso el proxy IP debe detectarlo en la respuesta del llamado ("Trying", "Ringing", "OK"...).
Proxy's RTP disponibles
Que yo conozca las opciones más extendidas (al menos en el mundo del software libre) son RtpProxy y MediaProxy, ambos compatibles con OpenSer y con SER, los dos proxy SIP por autonomasia.
Falsos mitos
Se suele leer a menudo el falso mito de que "si un usuario está tras NAT (sin usar STUN u otras soluciones NAT de lado de cliente) y otro con IP pública entonces no es necesario proxy RTP". Esto es completamente falso salvo con una excepción que comento luego.
Hace falta proxy RTP por la sencilla razón de que el usuario tras NAT no sabe porqué puerto va a salir nateado su audio y tampoco tiene forma de saberlo su proxy SIP así que no hay forma de que se lo pueda indicar al llamado (y da igual que el llamado tenga IP pública).
La excepción de la que hablaba se da (gracias a Jesús Rodríguez por la explicación) cuando el equipo que tiene ip pública soporta lo que se conoce como "Comedia". Esta funcionalidad, soportada por ejemplo por todos los gateways de Cisco, Sonus, etc, lo que hace es enviar el RTP a la IP y puerto en los que él recibe RTP, independientemente de lo que diga el SDP. Así, el RTP enviado por el gateway al usuario es aceptado por el cacharro que haga NAT, incluso con NAT simétrico.
He aquí una explicación bastante buena.
2 comentarios:
Muy muy clarito
Genial la explicacion!! Felicitaciones
Publicar un comentario en la entrada