Hoy vamos a ver como configurar OpenSIPS 1.6 y MediaProxy para solucionar los problemas que el NAT nos pueda traer.
Configurar el proxy para solucionar los problemas de NAT suele ser de las primeras cosas que se pretende o se hace al configurarlo, pero en muchas ocasiones se olvida el primer paso: entender el NAT. En su día escribí un post con una breve introducción al NAT, pero lo que os recomiendo es que os leáis varias veces éste post de Iñaki Baz Castillo explicando como afecta el NAT al protocolo SIP así así como los distintos tipos de soluciones.
En este post vamos a ver como “arreglar” el NAT con OpenSIPS 1.6 y MediaProxy. El módulo mediaproxy de OpenSIPS nos servirá en combinación con el propio MediaProxy para arreglar el SDP y hacer que el RTP pase por MediaProxy, mientras que para arreglar la parte de señalización utilizaremos el módulo nat_traversal.
El módulo nat_traversal
Este módulos nos servirá para arreglar la cabecera Contact de los mensajes SIP nateados y mantener el NAT abierto haciendo keepalive del lado servidor. El módulo nat_traversal tiene una particularidad que le diferencia de otros módulos similares: fue diseñado para tratar entornos multi-proxy, como por ejemplo el caso en que el proxy que mantiene el keepalive no sea el que gestiona los REGISTER (el registrar). No vamos a entrar en detalle en este post, pero conviene tenerlo en cuenta…
El módulo mediaproxy
Este módulo gestiona la comunicación con el servidor MediaProxy, de manera que el módulo modificara el SDP para que el audio pase por MediaProxy, que actuara de media relay. Como comente en un post anterior MediaProxy soporta ICE, por lo que podremos arreglar el NAT en prácticamente todos los casos (salvo los malditos ALGs).
Antes de empezar
Antes de comenzar la descripción de la configuración necesaria es importante comentar que en este post vamos a utilizar el método fácil. El módulo mediaproxy tiene 2 formas de funcionar:
- Funciones use_media_proxy y end_media_session: han de ser llamadas por el usuario, por lo tanto este ha de saber exactamente cuando quiere que MediaProxy comience o acabe su funcionamiento. Grosso modo tendremos que encargarnos del primer INVITE, los in-dialog-requests y el BYE. Lo veremos en otro post
- Función engage_media_proxy: utiliza el módulo dialog para llamar a las funciones del punto 1 internamente. El usuario solo tiene que llamar a la función engage_media_proxy en el primer INVITE y olvidarse, el resto se realizara internamente. El hecho de que sea tan fácil también trae algunas limitaciones, que veremos mas adelante.
Arreglando la señalización
Primero vamos a configurar el módulo nat_traversal, con el que podremos arreglar el NAT en la señalización.
loadmodule "nat_traversal.so"
...
modparam("nat_traversal", "keepalive_interval", 60)
modparam("nat_traversal", "keepalive_method", "OPTIONS")
modparam("nat_traversal", "keepalive_extra_headers", "X-Keepalive: yes\r\n")
modparam("nat_traversal", "keepalive_state_file", "/var/run/opensips/keepalive_state")
Con los parámetros indicados haremos que el módulo nat_traversal mande un mensaje SIP OPTIONS cada 60 segundos para mantener el NAT abierto. Ademas, añadiremos la cabecera X-Keepalive, simplemente para identificar estos paquetes mejor.
Para hacer que el módulo comience a enviar los OPTIONS será necesario que llamemos a la función nat_keepalive(). La particularidad de esta función es que no provoca que el mecanismo comience de inmediato, sino que será activado en caso de recibir/generar una respuesta positiva a un REGISTER o SUBSCRIBE y cuando un dialogo comience con un INVITE.
...
if ((method=="REGISTER" || method=="SUBSCRIBE" ||
(method=="INVITE" && !has_totag())) && client_nat_test("3"))
{
nat_keepalive();
}
...
Ademas del keepalive, también tendremos que modificar los mensajes SIP para que la cabecera Contact contenga la IP y puerto reales desde los que vino el paquete en lugar de lo que el terminal del usuario haya puesto. También añadiremos el parámetro rport a la cabecera Via, de manera que OpenSIPS anyadira la IP y el puerto desde los que recibió el paquete a la primera cabecera Via aunque el terminal no indicara soporte para rport. Para ello incluiremos lo siguiente en nuestro request route:
if (client_nat_test("3")) {
force_rport();
fix_contact();
}
Es posible que las respuestas también vengan nateadas, porque el terminal al que llamamos esta detrás de NAT así que tenemos que tratarlas en un onreply route:
if (client_nat_test("1")) {
fix_contact();
}
Ya solo nos queda una cosa para terminar con la señalización: fijar el AVP necesario para que OpenSIPS guarde la dirección IP y puerto desde la que se ha registrado el usuario en la tabla location de su base de datos:
modparam("registrar", "received_avp", "$avp(s:received_uri)")
...
$avp(s:received_uri) = $source_uri;
La pseudovariable $source_uri es exportada por el módulo nat_traversal y contiene la IP, puerto y transporte desde los que se recibió el paquete.
Arreglando el RTP
Una vez tenemos la señalización arreglada necesitamos hacer que el RTP pase por nuestro servidor MediaProxy. Para ello modificaremos el SDP de manera que la IP y puerto desde los que se supuestamente se enviara el RTP sean realmente el servidor de MediaProxy.
Como hemos comentado anteriormente vamos a utilizar el método fácil, por lo que solo tendremos que llamar a la función engage_media_proxy() para el primer invite:
if (is_method("INVITE") && !has_totag()) {
engage_media_proxy();
}
Limitaciones
Todo no puede ser perfecto, por lo que el método que aquí hemos utilizado puede no ser el mejor para todos los casos. En concreto estas son las limitaciones que el sistema utilizado conlleva:
- Se utilizara siempre MediaProxy: dado que la función engage_media_proxy() utiliza el módulo dialog para funcionar es necesario llamarla al comienzo del dialogo, así que llamarla al recibir un 200 OK nateado seria demasiado tarde.
- Manejo de múltiples diálogos: tanto OpenSIPS como MediaProxy sufren al recibir múltiples respuestas con SDP a un INVITE (dos 183 por ejemplo), por lo que los resultados son inesperados.
Dado que la mayoría de usuarios están detrás de NAT y que gracias a la arquitectura escalable de MediaProxy podemos ampliar los recursos a medida que los vayamos necesitando, tendremos que valorar la facilidad en la configuración frente a la flexibilidad en la gestión de NAT.
Happy NAT traversing!













