Iep!
SIP (SDP) y algo de networking 😉 ICE! (RFC5245) es el #topic de hoy.
Hoy por hoy, es más que habitual tener una solución de VoIP hosteada en nuestro datacenter y/o cloud vPBX. En dicho escenario, a parte de todas las opciones de superviviencia que hemos comentado varias veces por aquÃ, el media path es algo que nos preocupa siempre a todos.
En la parte de la unión con la red pública, no hay mucha magia negra, si recibimos el audio vÃa SIP Trunking, nuestro RTP realizará el path completo desde la ubicación del SIP UA hasta la ubicación del servidor, lo mismo si optamos por un PRI centralizado en una ubicación. La excepción al path completo es la presencia de un enlace PSTN local en cada sede, para poder conectar directamente el media localmente.
Caso de las vPBX
En las centralitas «virtuales», dónde  es «pan para todos», no es habitual tener soporte de gateways locales y se tiende a permitir el acceso desde redes no gestionadas, para no obligar al cliente a  tener túneles o conexiones especÃficas – a lo sumo se le recomienda tener una salida dedicada o gestionar bien su traffic shapping / QoS.
De la misma forma, se combinan redes diferentes tanto WAN como LAN, pudiendo llegar a esquemas tipo:
En estos escenarios, que levante la mano el integrador o desarrollador VoIP que nunca ha tenido escenarios de One-Way Audio 😉 Siendo indiferente que inviertas 60k en una solución top-vendor 😉 o eches a andar una solución opensource (no necesariamente más barata 😉 ).
De hecho, aún recordamos en el equipo VoIP de Irontec cuando una clienta estaba conectada desde una red con muchas pérdidas de paquetes – no controlada, y nos dijo «La VozIP es asÃ?«, desde entonces, se ha convertido en una frase-broma que recordamos habitualmente en los diagnósticos del equipo de soporte 😉
Es posible que se haya ganado infinito en integración y apertura, es posible que se haya gana infinito en gestión , pero el cambio de circuitos conmutados a paquetes IP y, añadiendo el componente Internet, en media paths garantizados no creo que nadie pueda decir que en global no hay muchÃsimas más peleas que cuando se pagaban circuitos ATM-WAN para lanzar E1-QSIG’s a precios millonarios entre las PBX de turno 😉
¿Por qué tanto lÃo con el NAT?
Para entrar en materia, recomendamos la lectura a partir de la página 39 de la documentación que liberamos hace bastante tiempo sobre SIP/VoIP/Asterisk en general, la verdad es que su momento le pusimos bastantes ganas, con esquemitas muy ilustrativos y todo jiji 😉 aquà van:
Realmente, el NAT no sólo es EVIL, sino que que es un demonio polimórfico 😉 , si, como aquel primer virus polimórfico del grupo 29A que tanto agradaba en antiguas épocas a nuestro verdadero Yoda del Norte 😉 NO hay un sólo tipo de NAT, ni mucho menos!, ni tampoco hay pocos routers con SIP ALG o UPNP (Que algunos incluso consideran que habrÃa que prohibir jiji).
ICE: La solución definitiva
No es nada nuevo, Saghul lo comentaba ya hace más de 6 años !!! Tal y como suele repetir N^M veces OEJ, la solución no estaba en el lado del servidor, no habÃa que repetir los errores de verticalización de las LegacyPBX de siempre, la solución está en la colaboración del SIP UA !  SIP World: The User is the King!
El proceso, muy resumido, se basa en las tecnologÃas ya existentes:
- SDP: Para describir la sesión que queremos establecer, esta vez con candidatos, que luego comentarmos.
- STUN: Nos permitirá obtener nuestra dirección IP pública y tipo de NAT,
- TURN: En casos extremos, como «intercambiador» público 😉
La idea, en súper breve: el SIP UAC descubre sus direcciones y las añade al SDP con diferentes prioridades (primero quiere hablar directamente a su IP privada tras el clásico NAT, luego a su IP WAN de salida, y si esto no funciona, al TURN Server), en el 200 OK se envÃan paquetes entre las diferentes IP’s hasta saber cuales son válidas y en función de la prioridad quedarse con una.
Estas dos referencias: la de Saghul y la de Olle son muy muy buenas en cuanto a esquemas y descripción detallada de cada paso.
RTPEngine: El Media KING !
La verdad es que la gente de SIPWISE se lo ha currado muchÃsimo con RTPEngine, no sólo por sus posibilidades de bridging entre clientes DTLS (WebRTC DTLS is mandatory) que están tan de moda, sino por sus más que interesantes features 🙂 Entre ellas, el soporte de ICE, para gestionarlo y/o añadirse como candidato 🙂
Esto es realmente killer, sobre todo porque es control-soft-seleccionable, es decir, desde el SIP Proxy que llama a RTPEngine, se puede indicar si queremos o no mantener los candidatos ICE y añadirnos o no, o directamente quitar todos.
Estado del Arte en cuanto a ICE en los SIP UA’s
A fecha de hoy, no es que podamos tocar campanadas a todo volumen, es posible que sea por su complejidad de implementación o tb porque en un escenario en el que sólo queremos salvar «nuestro lado», independientemente del media path: el ITSP que usemos seguramente haga media el nat traversal / media relay.
Sea como fuere, lo que hemos podido ver en cuanto al status actual:
Fabricante | Modelo | ICE Support Status (SIP) | Comentarios |
---|---|---|---|
Yealink | Todos los modelos compatibles con firmware v81. | Si | Gracias a Hassan Ali de SPC Universe por el firmware Beta para pruebas ! Dicho firmware será publicado en Sep 2016 |
SNOM | Todos | Soporte únicamente para firmware Lync | Gracias a Alberto Sagredo por la información. |
Cisco | Todos | No hay soporte en Cisco SMB. Si hay soporte en Cisco 78XX con 3rd Party Firmware. | Gracias a Joaquin Lopez por la info ! |
AG Projects | BLINK | Si | |
Counterpath | BRIA,XLITE | Si | |
JITSI | JITSI | Soporte únicamente para XMPP, no hay soporte de ICE en cuentas SIP. | |
BelleDone Communications | Linphone | Soporte completo | |
Servidores TURN-STUN
De forma independiente a soluciones «full built-in», existen varios servidores open source de calidad, entre ellos
- Resiprocate ReTurn Server
- rfc5766-turn-server.
- coturn (evolución del anterior).
- Jitsi Turn Server.
Lo que comparten todos entre sà es que son tanto STUN como TURN Servers, con sus respectivos usuarios.
Cabe destacar que para desplegar correctamente STUN, debemos tener 2 IP’s públicas usables.
Montando el escenario para un mini-lab
ReSiprocate Return en Debian Jessie
Quite easy 😉 Poco especial que comentar, está en los repos oficiales:
root@icestunturnzgor:~# apt-cache show resiprocate-turn-server | head -n 3 Package: resiprocate-turn-server Source: resiprocate Version: 1:1.9.7-5
Una vez  instalado, se configura en: /etc/reTurn/reTurnServer.config, dónde lo más destacado a comentar:
- TurnAddress y AltStunAddress: Dódne indicamos las IP’s públicas a usar.
- UserDatabaseFile: Para definir la ubicación del fichero de usuarios.
- LoggingLevel: Conviene ponerlo en Info si queremos ver lo que está pasando realmente.
Los usuarios se crean por defecto en: /etc/reTurn/users.txt, con la contraseña hasheada tal que:
root@icestunturnzgor:~# echo -n irontec:turn.irontec.com:superpassXD | md5sum 466d11u6f74nothere1c11b7wtfXD11ed2bea11
Para probarlo, tan fácil como, desde este cliente consola:
Probamos  la parte STUN
Con este cliente mismamente, con PIP tal cual (pip install pystun):
zgor@zhost:~$ pystun -H turn.irontec.com NAT Type: Full Cone External IP: 85.85.288.3327 ;) External Port: 54320
Esto tras una conexión con cablemodem default (Thomsom…).
Probamos la parte TURN
Para esto, podemos ir por ejemplo a esta URL de Test WebRTCÂ y definir que TURN Server queremos usar, clickando en el icono de settings:
y posteriormente, tras dara START Test, debemos acabar con:
Es decir, tenemos los 3 posibles candidatos 🙂
En el log del ReSiprocate Turn Server veremos algo similar a:
INFO | 20160806-120524.563 | reTurnServer | RETURN | 140124557031168 | TurnAllocation.cxx:44 | TurnAllocation created: clientLocal=[UDP 151.aa.XXX.27:3478] clientRemote=[UDP 85.XXXX.1FF8.AAA7:37943] allocation=... INFO | 20160806-120524.564 | reTurnServer | RETURN | 140124557031168 | TurnAllocation.cxx:114 | TurnAllocation refreshed: clientLocal=[UDP 151.aa.JJJ.27:3478] clientRemote=[UDP 85.CC.1E8.XXX7:37943] allocation= .. INFO | 20160806-120524.564 | reTurnServer | RETURN | 140124557031168 | UdpRelayServer.cxx:30 | UdpRelayServer started. [151.80.161.27:49154]
Muy bien, pues con esto tenemos validado que nuestro STUN/TURN Server funciona correctamente, podemos continuar con lo siguiente 🙂
Kamailio
Poco que comentar que no se haya dicho ya en N ocasiones, con los repos   es coser y cantar 🙂
No nos tenemos que preocupar de módulos, el módulo de control de RTPEngine que nos interesa está ya en el propio paquete principal:
dpkg -S rtpengine.so kamailio: /usr/lib/x86_64-linux-gnu/kamailio/modules/rtpengine.so
RTPEngine
Para Debian, es increÃblemente fácil:
git clone https://github.com/sipwise/rtpengine rtpengine ./debian/flavors/no_ngcp dpkg-buildpackage (está en dpkg-dev)
Si nos falta alguna dependencia ya nos irá avisando el propio sistema de Building de Debian.
Una vez acabamos con los paquetes necesarios para echarlo a andar:
ngcp-rtpengine_4.6.0.0+0~mr5.0.0.0_all.deb ngcp-rtpengine-daemon_4.6.0.0+0~mr5.0.0.0_amd64.deb ngcp-rtpengine-dbg_4.6.0.0+0~mr5.0.0.0_amd64.deb ngcp-rtpengine-iptables_4.6.0.0+0~mr5.0.0.0_amd64.deb ngcp-rtpengine-kernel-dkms_4.6.0.0+0~mr5.0.0.0_all.deb ngcp-rtpengine-kernel-source_4.6.0.0+0~mr5.0.0.0_all.deb ngcp-rtpengine-utils_4.6.0.0+0~mr5.0.0.0_all.deb
Una vez instalado, conviene validar que tenemos bien cargado el módulo para in-kernel packet forwarding:
root@rtpenginezgor:/usr/src# lsmod | grep RTP xt_RTPENGINE 26683 3 x_tables 27308 5 ip6table_filter,ip_tables,xt_RTPENGINE,iptable_filter,ip6_tables
La configuración en Debian, en su ubicación últimamente habitual: /etc/default/ngcp-rtpengine-daemon
Nos interesa principalmente:
LISTEN_TCP=127.0.0.1:25060 LISTEN_UDP=127.0.0.1:12222 LISTEN_NG=127.0.0.1:22222 LISTEN_CLI=127.0.0.1:9900 INTERFACES="public/151.80.XXX.YYY"
Con ello, tenemos definido que RTPEngine escuche en los puertos de control que queremos, y en loopback, para evitar problemas de seguridad, y definimos su IP Pública (la que anunciará en los SDP’s y utilizará).
Primeras pruebas
Para estas primeras pruebas vamos a utilizar un Yealink T46G con soporte ICE, y un softphone XLite, en redes inicialmente accesibles y finalmente totalmente separadas.
Algo tan simple como:
Configuración en ambos
La configuración en ambos, bastante trivial:
Prueba de llamada en red enrutada
En este primera prueba, realizamos la llamada entre XLite (10.10.4.66) y el Yealink con el firmware Beta (10.10.1.230).
Lo que es el call-flow:
Como se ve, nada realmente especial que comentar, salvo el ReInvite por parte del Xlite (SIP UAC en este caso), si los comparamos, gracias a nuestro amado SNGREP:
Como podemos observar, en la transacción inicial (INVITE) que inicia el diálogo, XLite propone tanto su IP nativa (host) como su public WAN IP (server reflexive), y, en su Reinvite, ya ha recibido tráfico por parte del terminal Yealink desde su IP Host tb (se intercambian tb con STUN), por lo que el terminal acaba diciendo que quiere hablar en su NIC nativa y que la IP origen desde la que recibe el tráfico ahà es 10.10.1.230, es decir: ICE ha hecho su trabajo perfectamente !
Cambio de red y prueba de llamada en redes independientes 100% aisladas
Muy bien, hasta aquà todo «fácil», si no hubiera existido ICE tb hubiera funcionado, su IP’s plenamente accesibles, pero que pasa si les aislamos?
Pasamos al escenario del esquema (el de la derecha), y de nuevo, el flujo:
Por comentar el flujo: En el centro el Kamailio (sin media proxy, ni nada), y en los lados las IP’s de WAN de salida diferentes, esta vez hemos optado por poner aliases en sngreprc 😉
Se observa el mismo ReInvite, escogiendo al mejor candidato
Peroooooooooooooo:
¿Cómo es posible que haya audio bidireccional sin media proxy y sin haber realizado ningún tipo de NAT? ¿WTF?
Esto es posible porque estamos ante un full-cone nat 😉 Si, lo que decÃamos, NAT es una bestia de múltiples caras, más allá del clásico port-fowarding. Estamos ante este esquema exactamente:
El cliente SIP, gracias a STUN, ha conseguido saber su IP Pública, y, gracias a las siguientes fases de STUN ha conseguido saber que está en un NAT Fullcone y «se ha quedado» con el puerto allocateado 😉
Si, asà es la vida, cualquiera que mande tráfico hacia esa WAN:PUERTO está permitido hacia dentro 😉
De hecho, si miramos desde la perspectiva diferenciada de ambos usuarios SIP:
Perspectiva XLite (UAC)
Activamos sngrep con -r y vemos el flujo rtp:
Perspectiva Yealink
Continuando con las pruebas con RTPEngine
En la fase anterior, hemos visto que dos usuarios SIP pueden hablar entre ellos perfectamente, simplemente con la ayuda de un STUN Server.
¿Pero que pasa por ejemplo con los Fortinet? Por defecto no activan el comportamiento Full Cone, debe hacerse a mano, desde el CLI, acorde al handbook de FortiOS:
Es decir, en este escenario, no habrÃa forma de hacer el nat piercing desde ambos lados a la vez.
Soluciones:
Configuración en Kamailio para invocar RTPEngine
La documentación del módulo, como siempre en el proyecto Kamailio, muy detallada, nos indica claramente:
Asà que para probar, con la configuración por defecto de Kamailio mismamente, en la ruta de NAT_MANAGE, podemos añadir:
Overwrite de todo y único candidato RTPENGINE (ICE=force)
if (has_body("application/sdp")) rtpengine_manage("ICE=force");
Con esto, el flujo general, desde la perspectiva del servidor Kamailio:
De este gráfico, cabe destacar que el RTPEngine, tiene que saber el origen del cliente Yealink, que saldrá tras NAT, y se hará el «learning» de su puerto público.
Al recibir tráfico «early» desde el cliente XLite (tras WAN2), decide hacer el relay del RTP hacia la IP del SDP del 183 inicial, hasta que hace el proceso comentado de aprendizaje de su IP y puerto, y entonces y sólo entonces cambia el destino del RTP.
Si comparamos los SDP’s que nos llegan del INVITE:
y del 200 OK:
Respetar ICE y añadirse únicamente como candidato relay
if (has_body("application/sdp")) rtpengine_manage("ICE=force-relay);
El diálogo completo nos quedarÃa tal que:
Como vemos, a pesar de haber activado la captura RTP, no se ve ni un sólo paquete, ya que RTPEngine se ha añadido  como candidato relay, al ser ambas conexiones full cone NAT, el candidato ICE de tipo Server Reflexive ha ganado la negocicación y el audio va entre ellos 🙂
Realmente, este serÃa el caso buscado generalmente, asà podemos conseguir que el media path de Alice y Bob sea «el best of»:
Concluyendo …
De ICE se puede hablar muchÃsimo, de hecho, basta con buscar un poco de info – NO necesariamente SIP RELATED – para encontrar muchÃsimas referencias que lo explican francamente bien, nos quedamos con estas como referencias ampliadas a este humilde post:
- WebRTC Fundamentals de Elastricrtc.
- STUN, TURN & ICE for NAT Traversal de Eyeball.
- STUN, TURN, ICE, UPNP, ALG y otros del lado oscuro de la telefonÃa IP, gran post muy muy detallado de nuestro cercano Tartanga, por Enrique del RÃo.
Trickle ICE
La verdad es que el path de ICE si que es solución definitiva, buscar el P2P es siempre mejor, al contrario que tender a centralizarlo siempre todo, ahora con mediaproxys y tal, en escenarios internacionales con saltos cross-oceánicos, es un camino hacia el delay; de hecho, en la galaxia WebRTC es todo mandatory lo que respecta ICE.
Sin embargo, lo que si es cierto es que desde el punto de vista de la usabilidad, los tiempos de candidate gathering pueden ser muy altos – sobre todo si estamos con por ejemplo interfaces VPN levantados que no tienen conectividad con el endpoint contrario.
Por ello, Trickle ICE, con  el envÃo progresivo de candidatos ha emergido como la solución evolucionada, en este post de Emil Ivov (con intro del grandÃsimo WebRTC Master Victor Pascual)
Pues nada, nada más por hoy en estos lares !
PD Final: Todas las IP’s que hemos puesto aqui, las hemos apagado, ya no existen, asà no nos liábamos a tener que hacer el masking de los datos de IP’s 😉 😉
1 Comentario
¿Por qué no comentas tú también?
Como siempre, grande el artÃculo! Para enmarcarlo!
Ilustrativo, pedagógico y bien explicado.
Toca leerlo de nuevo con más calma, pero chapeaux!
Elio Rojano Ruiz Hace 8 años
Mola. Bien explicado Zgor.
manwe Hace 8 años
[…] NAT en SIP se ha hablado largo y tendido en todos lados, incluso por aquà hemos comentado tb algo, creo que cualquier ingeniero de voz ip la primera vez que habla con el ingeniero de redes […]
SIP Behind NAT: Engañar al NAT con más NAT - Blog Irontec Hace 7 años
Queremos tu opinión :)