Las extensiones internas se bloquean cuando el acceso a internet se cae. ¿Cómo resolverlo?

29 Jul

Este es un problema viejo y aunque la solución puede encontrarse buscando por internet, quise tomarme unos minutos para escribir un breve post que habla del problema y como resolverlo.

Estoy seguro que a varios les ha pasado: tienes tu conmutador configurado perfectamente y todo marcha bien. De pronto, de la nada, tus extensiones internas se caen: no haces ni recibes llamadas. Revisas un poco y te das cuenta de que no tienes internet. ¿Pero para que necesito internet si mis extensiones son internas? ¿Qué tiene que ver una cosa con la otra? Es ahí donde entramos.

El problema radica en la manera en como Asterisk resuelve los dominios de las troncales SIP a donde necesita conectarse. El canal SIP utiliza un método de consulta de DNS síncrono, lo que quiere decir que cuando llega una petición de resolver un DNS (ej. siptrunk.alianza.com) el canal SIP le pregunta al servidor DNS, espera la respuesta, y cuando finalmente la obtiene continú con su siguiente petición SIP. En un mundo ideal esto no es problema, ya que la resolución por DNS es muy rápida y toma unos cuantos milisegundos, por lo que normalmente no la notamos. Pero… ¿qué ocurre cuando por alguna falla en internet, el servidor de DNS al que solemos apuntar se cae o simplemente no podemos acceder a él? Pues la respuesta es que esto provoca un efecto  dominó en Asterisk que ocasiona que todo el canal SIP se caiga.

¿Cómo puede pasar esto?

Imagina el siguiente caso:

  1. Juan quiere hacer una llamada a través de su troncal de pbx.micarrier.com, así que levanta su teléfono y llama al número deseado.
  2. Asterisk recibe la petición de llamada y le manda a su DNS la solicitud de resoler pbx.micarrier.com, pero al utilizar paquetes por UDP, Asterisk no se da cuenta de que el equipo está offiline, así que le da un cierto tiempo de timeout a que el servidor responda.
  3. Mientras que Asterisk espera a recibir la respuesta, Jorge desea hacer una llamada a través de pbx.miotrocarrier.com, pero aún no puede enviar la llamada porque Asterisk está ocupado con la petición anterior.
  4. Para cuando Juan por fin recibe la respuesta de request timeout, Jorge ya lleva buen rato esperando a que su petición apenas comience, así que muy probablemente Jorge reciba un timeout pero a nivel de SIP, porque Asterisk se tardó mucho en responderle por estar ocupado en la petición de Juan.
  5. Si a este escenario le agregan más usuarios y más carriers, el sistema se hace más complejo exponencialmente, ocasionando una serie de retrasos que eventualmebte tiran todo el servidor porque nada responde (todos se quedan esperando a todos y ninguna llamada logra salir).

Esto es un problema a nivel de código de Asterisk: si las peticiones fueran asíncronas la espera de uno no se convertiría en la espera del otro y todos serían felices. Pero como se menciona en los foros de desarrollo de Asterisk, esta es una funcionalidad que requiere mucho tiempo para ser resuelta, y que al menos en la versión 1.8.21.0, persiste.

¿Cómo lo resolvemos?

Hay algunas soluciones:

  • Editar manualmente el /etc/hosts y poner allí todos los dominios y direcciones IP que necesitemos. El problema es que esto no funciona para resolución inversa de DNS, así que tiene fallos. Otro problema es que tendríamos que agregar manualmente cada dominio, lo cual puede consumir mucho tiempo, además de que si el proveedor actualiza su IP, nuestra resolución fallaría.
  • Configurar en Asterisk las IPs fijas de cada carrier. Fácil de hacer pero de igual manera, es manual, así que nos exponemos a los problemas de tener que estar vigilando nuestro PBX constantemente.

La solución que mas predomina es la de instalar localmente (en el mismo servidor de Asterisk) un servicio de cache de DNS, como es el caso de bind. Esto hará que el equipo almacede de manera local la información de consulta frecuente para que en caso de fallos con el internet, Asterisk sobreviva del cache. Y es bastante fácil de hacer.

En CentOS/RedHat lo hacemos fácil:

yum install bind bind-utils bind-libs caching-nameserver

En Debian/Ubuntu, también es sencillo:

apt-get install bind9

En CentOS/RedHat, por default el servicio no arranca automáticamente, así que debemos decirle a Linux que lo arranque cuando el sistema prenda.

chkconfig named on

También aprovechamos y lo arrancamos:

/etc/init.d/named start

Con esto el servicio de named ya está corriendo. Ahora le decimos a Linux que lo utilice. Editamos el archivo /etc/resolv.conf y nos aseguramos que solamente contenga una linea como la que sigue:

nameserver 127.0.0.1

Si usamos Elastix, hacer el cambio también desde la interfaz web. Abrimos el menu de System > Network y editamos la configuración para dejar únicamente un DNS:

DNS en Elastix

De esta manera, obligamos a que use el local. Si el local falla, lo peor que pasa es que perdemos nuestra troncal, pero es mejor recibir una respuesta negativa del DNS a no recibir respuesta.

Podemos validar que todo está corriendo revisando que el puerto 53 esté ocupado por el servicio de named:

[root@pbx ~]# netstat -anpl | grep 53
tcp        0      0 0.0.0.0:9090                0.0.0.0:*                   LISTEN      3953/java
tcp        0      0 127.0.0.1:53                0.0.0.0:*                   LISTEN      4745/named
tcp        0      0 127.0.0.1:953               0.0.0.0:*                   LISTEN      4745/named
udp        0      0 127.0.0.1:53                0.0.0.0:*                               4745/named

Y claro está, no puede faltar la super prueba del ping que muestre que los dominios resuelven correctamente:

[root@elastix ~]# ping asteriskmx.com
PING asteriskmx.com (216.93.172.112) 56(84) bytes of data.
64 bytes from 216.93.172.112.servepath.com (216.93.172.112): icmp_seq=1 ttl=53 time=74.6 ms
64 bytes from 216.93.172.112.servepath.com (216.93.172.112): icmp_seq=2 ttl=53 time=74.5 ms
64 bytes from 216.93.172.112.servepath.com (216.93.172.112): icmp_seq=3 ttl=53 time=74.9 ms

--- asteriskmx.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 74.563/74.723/74.912/0.265 ms

Hecho estos sencillos pasos, tu sistema estará preparado para caidas en el internet y tus troncales SIP no causarán que todo tu sistema se muera.

Solo una nota final: el servicio de named/bind al parecer vacia su cache cuando arranca. Esto quiere decir que si se va la luz y el internet al mismo tiempo, perderás la conectividad y todo se caerá (lo siento, no hay solución universal), pero en caso de que eso pase todo lo que necesitas hacer es detener el servicio y con esto tus DNS fallarán inmediatamente, con lo que te quedarás sin troncales SIP pero no si extensiones locales.

¡Suerte!

Christian Cabrera

Soy ingeniero en comunicaciones con especial interés en el área de voz sobre IP y tecnologías sobre información. He usado Asterisk de manera diaria desde hace más de 18 años. En el 2011 co-fundé Enlaza Comunicaciones, una empresa que se especializa en brindar servicios profesionales de consultoría sobre voz sobre IP basadas en Asterisk, así como servicios de interpretación simultánea y traducción.