Modelo de seguridad en Asterisk (parte 3 de 3)

8 Mar

Fuente: http://static.internetblog.org.uk/files/manjail.jpg


Llegamos al final de nuestras entregas discutiendo el modelo de seguridad de Asterisk. En la primera parte discutimos sobre la seguridad antes de llegar al conmutador, normalmente a cargo del firewall de nuestro acceso a internet. En la segunda partehablamos sobre como autenticar a los usuarios para permitirles acceder a nuestro sistema. En esta tercera entrega hablaremos sobre como limitar las características de los usuarios que ya se encuentran autenticados dentro de Asterisk.

Seguridad de operación

Existen errores en versiones anteriores de algunas interfases gráficas (léase: Elastix) que nos permitían leer la lista completa de extensiones del conmutador y sus contraseñas aún si el usuario no pasaba la autenticación de administrador. Esto quiere decir que a pesar de cerrar nuestra interfaz administrativa y que nadie pueda modificarla, al tener los usuario/contraseñas podría tomar un teléfono, registrarlo con estos datos y empezar a hacer llamadas. Peor aún: podría vender estos datos para que algún tercero haga llamadas ilegalmente desde nuestro equipo. Asumiendo que ya cometimos los errores de las otras 2 etapas, ¿cómo podemos evitar (o al menos reducir) el daño inminente?

El primer paso, es limitar los accesos de las extensiones de acuerdo a lo que deban hacer. Por ejemplo, es probable que la recepcionista necesite poder llamara a locales, LD y celulares. Sin embargo, ¿por qué la extensión que está en la cafetería tendría la necesidad de marcar hacia afuera? Limitar esto es muy sencillo haciendo uso de contextos:

[codesyntax lang=»bash» title=»extensions.conf»]

[internas]
exten => _XXXX,1,Dial(SIP/${EXTEN})

[locales]
include => internas
exten => _ZXXXXXXX,1,Dial(DAHDI/g0/${EXTEN})

[largadistancia]
include => locales
exten => _01NXXXXXXXXX,1,Dial(DAHDI/g0/${EXTEN})

[/codesyntax]

En este ejemplo, tenemos 3 contextos: [internas], [locales] y [largadistancia]. Cada uno incluye al anterior y además, agrega un grado más de permisos. La idea es que al configurar cada usuario SIP/IAX de nuestro sistema, limitemos los accesos que cada uno tenga, sabiendo que cada uno solo puede marcar estrictamente a lo que nosotros le permitimos, además de tener la facilidad de que al conceder un permiso superior, daremos acceso a lo anterior.

Es altamente recomendable que si no hacemos llamadas internacionales, entonces… ¡no las habilitemos! Si sabemos que nuestros negocios se centran en territorio nacional y quizá llamadas a EUA/Canadá, limitemos agregando el _001NXXXXXXXXX, pero no agreguemos algo tan general como permitir _00., que estaríamos dándole la oportunidad al atacante de que use el mundo entero. Recuerden que limitar las posibilidades improbables reduce el probable riesgo.

Una manera mucho más elegante sería hacer uso de Realtime para que al marcar, se consulte la BD para determinar si tenemos permisos de marcar a ese destino o no, y en base a eso reaccionar. Dado que Realtime es un poco más avanzado, lo veremos más adelante en otro artículo.

El segundo paso consistiría en poner limitantes no al teléfono sino a la persona. La manera de hacer esto sería obligar a quien marca a proporcionarnos un código que le autorice a marcar a ese destino. Si alguien puede marcar por nuestro sistema, al menos obliguemoslo a que se sepa las contraseñas de los usuarios. Usando el mismo ejemplo anterior, lo podríamos hacer así:

[codesyntax lang=»php» title=»extensions.conf»]

[internas]
exten => _XXXX,1,Dial(SIP/${EXTEN})

[locales]
include => internas
exten => _ZXXXXXXX,1,Macro(salida,DAHDI/g0/${EXTEN})

[largadistancia]
include => locales
exten => _01NXXXXXXXXX,1,Macro(salida,DAHDI/g0/${EXTEN})

[macro-salida]
exten => s,1,Authenticate(/etc/asterisk/pinset)
exten => s,n,Dial(${ARG1} )
exten => s,n,Hangup

[/codesyntax]

En el ejemplo de arriba estamos introduciendo un nuevo elemento, un macro que nos permitirá hacer 2 pasos en uno solo: la autenticación y luego la marcación. De acuerdo al ejemplo, cualquiera podria marcar extensiones locales sin restriccion (al final de cuentas, son gratis). Sin embargo, si trata de marcar a llamadas locales o larga distancia se le pedirá al usuario que ingrese un código (el cual estaría escrito dentro del archivo /etc/asterisk/pinset). Si el usuario no proporciona la contraseña correcta, la llamada termina.

Los 2 esquemas que hemos mencionado (contextos y contraseñas) deberían impedir que algo malo pase. Sin embargo, si en el peor de los casos alguien logra penetrar todo lo anterior, limitemos la cantidad de daño recibido. ¿Cómo? Limitando la cantidad de llamadas simultáneas que puede hacer. Este paso es sumamente importante ya que, para empezar, nadie tiene por que poder hacer 20 llamadas simultáneas, ¿o si?

Para hacer esto, reaprovechemos el ejemplo anterior:

[codesyntax lang=»php» title=»extensions.conf»]

[internas]
exten => _XXXX,1,Dial(SIP/${EXTEN})

[locales]
include => internas
exten => _ZXXXXXXX,1,Macro(salida,DAHDI/g0/${EXTEN},2)

[largadistancia]
include => locales
exten => _01NXXXXXXXXX,1,Macro(salida,DAHDI/g0/${EXTEN},1)

[macro-salida]
exten => s,1,GotoIf($[${GROUP_COUNT(${CALLERID(num)})}>=${ARG2}]?Permite)
exten => s,n,Congestion()
exten => s,n(Permite),Set(GROUP(${CDR(uniqueid)})=${CALLERID(num)})
exten => s,n,Authenticate(/etc/asterisk/pinset)

exten => s,n,Dial(${ARG1} )
exten => s,n,Hangup

[/codesyntax]

Notarán que el macro se ha hecho bastante más complejo. Hay una buena razón para esto:

Hemos agregado al Macro la posibilidad de determinar cuantas llamadas simultáneas activas tiene un usuario en un momento dado, y si se excede de esta cantidad, corta la llamada.

Observen esta línea:

[codesyntax lang=»php»]

exten => _ZXXXXXXX,1,Macro(salida,DAHDI/g0/${EXTEN},2)

[/codesyntax]

El 2 que está al final de la línea es la cantidad máxima de llamadas a ese tipo de destino que estamos permitiendo. En el ejemplo anterior, permitimos que alguien marque hasta 2 llamadas locales al mismo tiempo, pero solo puede marcar a una LD. No sería muy difícil seguir este patrón para limitar el acceso internacional, pero eso se los dejo a ustedes para que practiquen.

 

Conclusiones

Si sumamos todas las barreras que hemos puesto con estos 3 niveles de seguridad, al final obtenemos:

  • Cerrar el acceso por firewall externo a nuestro conmutador
  • Detener el acceso al conmutador por firewall interno (iptables)
  • Acortar el rango de IPs desde las que pueden registrarse los usuarios SIP/IAX
  • Bloquear a aquellos usuarios que intenten fuerza bruta contra nosotros
  • Activar solo el plan de llamadas  necesario
  • Restringir  al usuario dependiendo de si sabe la contraseña correcta para el destino o no
  • Reducir la cantidad de llamadas simultáneas que el usuario puede hacer

Lo mejor de estas reglas es que son acumulables. Mientras más de ellas usemos lograremos un conmutador más y más seguro. Inclusive si consideramos que llevar a cabo todas resulta difícil, aplicar tantas como se pueda nos garantizará que estaremos restringiendo la posibilidad de que algo salga mal.

Créanme: vale más invertir tiempo en tomar en cuenta estos pasos en lugar de tener que pagar la cuenta final.

¡Suerte!

Modelo de seguridad en Asterisk (parte 2 de 3)

6 Mar

El día de ayer publicamos la primera de esta serie de entregas que buscan concientizar sobre los 3 diferentes niveldes de seguridad en un conmutador IP como lo es Asterisk. Discutimos sobre la seguridad de acceso al sistema, que es la primer barrera contra la quenos anfrentamos al acceder al equipo. Para esta entrega hablaremos del segundo nivel de seguridad, es decir: los atacantes ya pueden llegar hasta el equipo, ¿cómo podemos defendernos de lo que nos pueden hacer?

Seguridad de autenticación

Como mencioné en el párrafo anterior, esta es la segunda capa de protección contra atacantes externos: ya penetraron nuestra red, ya pueden «ver» nuestro conmutador. ¿Quiere eso decir que estamos a su merced? Obviamente no, pero debemos tener algunos aspectos muy importantes en cuenta para que esto no nos pase. De entre los puntos a mencionar, resaltemos estos:

  • Listas de acceso para usuarios SIP/IAX
  • Contraseñas SIP/IAX seguras
  • Defensa contra fuerza bruta

Listas de acceso

Esta es, sin duda, la característica mas evitada en seguridad de Asterisk: configurar listas de acceso que hagan una coincidencia con los dispositivos que deben/pueden registrarse en nuestro sistema, limitando el acceso a ciertas extensiones desde ciertas IPs.

Por ejemplo: si nuestra red interna está en el segmento 192.168.1.0/24, ¿por qué razón habríamos de permitir que la extensión que pertenece a la sala de juntas se registre desde la IP 189.200.45.13? Las listas de acceso nos permiten restringir desde que IP puede un dispositivo registrarse o hacer llamadas con nosotros. Esta es la única manera que tienen de hacer que solo ciertas extensiones puedan ser usadas desde afuera de nuestra red (usuarios móviles), mientras que el resto no (usuarios locales)

Las listas de acceso en Asterisk se configuran usando los campos de permit y deny dentro ya sea de la sección [general] o bien dentro de la configuración de cada usuario (esto aplica para sip.conf y para iax.conf). Tomen en cuenta que el orden si importa y que la metodología default es un permit any. Esto quiere decir que si no negamos la autenticación, se le permite el paso a todo. Observen el siguiente ejemplo:

[codesyntax lang=»ini»]

[100]
username=100
type=friend
context=default
secret=aBcDeF12345!
deny=0.0.0.0/0.0.0.0
permit=192.168.1.1/255.255.255.0

[/codesyntax]

 

En este ejemplo, la regla de deny=0.0.0.0/0.0.0.0 está negando el paso a todo, ya continuación el permit=192.168.1.1/255.255.255.0 está permitiendo el paso solamente a aquellos dispositivos que se encuentren dentro de la red 192.168.1.x. Tengan mucho cuidado ya que si invertimos el orden de declaración:

[codesyntax lang=»ini»]

[100]
username=100
type=friend
context=default
secret=aBcDeF12345!
permit=192.168.1.1/255.255.255.0
deny=0.0.0.0/0.0.0.0
[/codesyntax]

Al final, el deny (que es lo último declarado) prevalecerá, y dado que 0.0.0.0/0.0.0.0 hace match con todo, estamos negando el paso a todos (haciendo que la extensión no sirva).

También pueden usar la notación CIDR, por lo que pueden declarar un rango de red como 192.168.1.1/24 y es igual que 192.168.1.1/255.255.255.0.

Recuerden que al declarar el permit/deny dentro de [general] están habilitando esa regla para todos, pero si solo colocan reglas de permit individuales dentro de cada usuario, abrirán ese usuario solamente. Esta es la única manera que tendrán de permitir el acceso remoto a usuarios SIP/IAX específicos, negando la posibilidad a todos los demás. Esto resulta muy conveniente porque no exponen todas sus extensiones, sino solo las estrictamente necesarias.

Al tener que descuidar y permitir el paso a ciertos usuarios, deben asegurarse de que las contraseñas de aquellos usuarios a los que les permiten acceder desde el exterior son suficientemente seguras, y de ahí viene el siguiente punto.

 

Contraseñas SIP/IAX seguras

Un motivo que muchos administradores tienen para dejar contraseñas inseguras es por facilitarse la labor al momento de configurar sus dispositivos SIP. Lo que muchas personas desconocen es que las contraseñas SIP/IAX se hicieron para tener que teclearlas una única vez, y esto es cuando configuramos el dispositivo (de hecho, si hacemos la configuración por provisionamiento TFTP nunca tendremos que teclearlas, pero ese es material para otro artículo). Si la contraseña solo deble escribirse o copiarse una única vez, entonces no existe razón para aprovechar y echarle un poco más de tiempo en usar contraseñas que sean tan seguras que un sistema de fuerza bruta no pueda romper.

Existen muchos mecanismos sencillos para generar contraseñas aleatorias. Quizá uno disponible que cualquier sistema con Linux tendría (con el paquete de openssl instalado):

[codesyntax lang=»bash» title=»Desde el Linux CLI:»]

# Esto generará 20 contraseñas aleatorias de 12 caracteres
for i in {1..20}; do openssl rand -base64 12; done

[/codesyntax]

Podemos fácilmente cambiar el 20 por cualquier otro número y generar un pool de contraseñas aleatorias que podemos ocupar para nuestras extensiones, asegurándonos con esto de que nuestras contraseñas sean totalmente seguras.

También tomemos en cuenta peores casos: si no colocamos una contraseña en una cuenta IAX estaremos abriendo la posibilidad de que cualquier entidad que llegue a nuestro equipo aún y si no proporciona contraseña sea autenticado inmediatamente. Esto es por la propiedad de IAX que se basa totalmente en la contraseña para realizar la autenticación de un dispositivo. Si no llenamos este campo, cualquiera se podrá autenticar como tal, aún y sin proporcionar ningún dato.

El hecho de tener contraseñas seguras impedirá que los atacantes entren a nuestro sistema. Sin embargo, no impedirá que lo intenten. Aquí está la última parte de este rompecabezas:

 

Defensa contra fuerza bruta

Es un hecho: si nuestro equipo debe estar expuesto porque nuestros usuarios así lo requieren, entonces tarde o temprano será atacado. El ataque puede verse en la forma de cientos de intentos de registro que intentarán adivinar nuestra contraseña segura definida en el punto anterior. A pesar de que sabemos que nunca la encontrarán, tantos cientos (o miles) de intentos pueden generar un ataque DoS en nuestro conmutador. ¿Cómo defendernos ante esto?

La respuesta es un sencillo (pero eficiente) programa llamado fail2ban. El fail2ban es una herramienta que analiza logs de intentos de ataque y bloquea selectivamente por iptables a la IP que origina estos ataques. Es como traer la seguridad de acceso cuando alguien ya entró a nuestro equipo pero se delató proporcionando contraseñas equivocadas. Veanlo como el personal de seguridad que te saca del lugar por comportarte mal, permitiéndote bloquearlo a nivel de firewall por unos minutos, horas o de manera permanente, todo depende de como lo configures.

Si estás interesado en ver como puedes configurar fail2ban y los filtros que puedes aplicar, puedes consultar el artículo que escribí hace unos meses.

 

Con esto cubrimos el segundo nivel en esta serie de entregas. En la siguiente discutiremos sobre la manera en como autenticar no a los dispositivos, sino a los usuarios, que son los últimos elementos en la cadena de seguridad de nuestro sistema.

¡Suerte!

Modelo de seguridad en Asterisk (parte 1 de 3)

5 Mar

Fuente: http://upload.wikimedia.org/wikipedia/commons/5/5b/Firewall.png

Desafortunadamente y como hemos comentado en otros posts, la seguridad en Asterisk es algo que se ha visto sobrevalorado por la sencillez y rapidez que trae el dejar un sistema que funciona en unas cuantas horas a partir de una distribución todo integrado, pero que es inseguro por descuidos del administrador.

¿Cómo puede alcanzarse la seguridad al 100% del conmutador? La respuesta es no se puede. Sin embargo, lo que si podemos hacer es llevar nuestro sistema a un nivel de seguridad que haga que aquel que intente penetrarlo sin autorización tenga que invertir más tiempo del que está dispuesto a ceder.

Para explicar mejor esto, definiremos el modelo de seguridad de Asterisk en 3 niveles:

  1. Seguridad externa (acceso al sistema)
  2. Seguridad de autenticación
  3. Seguridad de operación

Seguridad externa

Todo acceso al sistema desde fuentes externas (WAN) debe estar restringido a través de un firewall. Idealmente, usaríamos un firewall en hardware, pero si nuestro proveedor nos entrega una IP directa y la configuramos en nuestro equipo, podemos hacer uso de iptables.

Cuando decidimos que puertos abrir en nuestro firewall, debemos hacernos las siguientes preguntas:

  • ¿Habrá extensiones externas?
  • ¿Habrá alguna administración externa del conmutador?
  • ¿Existe algún proceso externo que controle el conmutador (manager interface)?

El tema de las extensiones externas es delicado, ya que es una parte fundamental de las ventajas de Asterisk pero al mismo tiempo es lo que permite el mal uso del conmutador. Si no pensamos tener extensiones externas, los puertos UDP 5060 y 4569 (SIP e IAX) deben estar cerrados. Si no abrimos los puertos, nadie ajeno al sistema, aún sabiendo las contraseñas de las extensiones podrá hacer llamadas. Al cerrar los puertos, cortamos el cable de acceso, y nada puede pasar. Es por eso que esta es la parte más importante de seguridad del sistema.

Si nos encontramos bajo el escenario que debemos tener extensiones externas, tenemos que asegurarnos que el nivel de seguridad secundario sea bueno, ya que al conceder acceso a entidades externas, debemos dejar la responsabilidad de la seguridad a las capas interiores. De esto nos encargaremos en la parte 2 de este artículo.

Nota: Al momento de hacer un register hacia una entidad SIP/IAX2 externa estaremos abriendo una sesión a través del firewall, lo que permitiría a esta entidad enviarnos llamadas a pesar de que el firewall esté cerrado. Hay que tomar esto en cuenta pues si alguien tuviera acceso administrativo a nuestro equipo podria generar un register hacia su propio conmutador y con ello, enviarnos llamadas en sentido inverso. El caso es muy raro, pero puede ocurrir. Ténganlo en cuenta.

Si necesitamos contar con administración remota del equipo debemos decidir correctamente que tipo de seguridad proveer. Si utilizamos alguna interfaz gráfica como FreePBX nunca, pero nunca debemos abrir el puerto HTTPS (TCP 443). Abrir el puerto 443 permitiria que cualquier vulnerabilidad de nuestra web, ya sea por FreePBX, Webmin, phpMyAdmin o cualquier otra interfaz que nos exponga contra atacantes externos.

Sobre este punto debo decir que dadas múltiples vulnerabilidades que han sido encontradas en interfaces gráficas, ningún administrador que considere su trabajo digno dejaría expuesto el puerto de HTTPS. Si acaso se necesita (para la administración), lo correcto es usar un túnel SSH o mejor aún, una conexión por VPN (sobre este último punto, si creamos una VPN podríamos no tener que abrir ni un solo puerto entrante en el firewall, por lo que este resultaría el caso más seguro de todos).

Por último, si tuviéramos necesidad de controlar Asterisk a través del Manager Interface (AMI), es necesario saber que toda la comunicación por este puerto siempre viaja sin encriptación, por lo que si alguien intercepta los paquetes del AMI podría fácilmente controlar completamente nuestro conmutador, creando extensiones o solicitando llamadas de la nada. El puerto que se ocupa para esta comunicación es el 5038 TCP y por lo tanto, nunca deberíamos dejarlo expuesto en nuestro firewall.

 

Este es el final de la primera de tres entregas sobre el modelo de seguridad de Asterisk. En las siguientes 2 partes haremos mención de como configurar ACLs dentro de Asterisk para asegurar el acceso, así como las opciones que debemos tomar en cuenta al momento de generar contraseñas seguras para acceso a nuestros usuarios SIP/IAX.

Recuerden que también pueden dejarnos sus comentarios a través de Twitter o Facebook.

¡Suerte!

El carrier no siempre tiene la razón

1 Mar

(por cuestiones de confidencialidad no puedo revelar nombres, pero esta historia aplica en general)

Desde el pasado noviembre recibí una llamada de uno de mis clientes indicándome que su equipo Elastix muy frecuentemente le daba el ya conocido mensaje «todos los circuitos se encuentran ocupados«. Su enlace con la PSTN era a través de un enlace digital E1 ISDN.  Pensé que algo estaría mal con la configuración del equipo, así que decidí acceder a la consola para ver que era lo que lo ocasionaba.

Intentó varias llamadas a un mismo número: todas fallaron. Mi creencia fue pensar que Elastix estaba mal interpretando el código Q.931 que el carrier entregaba de vuelta tras el resultado de la llamada. Para quienes no saben, el Q.931 es el protocolo estándar de la ITU para la señalización de control de conexión en ISDN (en otras palabras, es el responsable de indicar el estado de una llamada generada a través de un E1 ISDN). Por default, Elastix interpreta prácticamente todo con la misma respuesta de «todos los circuitos se encuentran ocupados», por lo que a pesar de que la razón de terminado de la llamada sea una congestión del carrier o bien que el número marcado no existe, siempre obtenemos la misma respuesta.

Implementé la solución de uno de mis post anteriores esperando que eso resolviera el problema y el cliente se enterara de cual era la verdadera razón para la desconexión. Poco tiempo paso cuando mi cliente me indicó que no hubo cambio, sino que todo continuó exactamente igual que al principio (mismo mensaje para todos los casos). Esto me extrañó dado que esta solución ha sido exitosa en muchos casos e inclusive, otras empresas lo han sugerido a sus clientes para resolver problemas con el servicio recibido por otros carriers, por lo que tuve que indagar más para encontrar la causa del problema.

Tras analizar los logs, encontré cientos de registros como este:

[Feb 9 08:34:03] VERBOSE[10458] pbx.c:     -- Executing [continue@macro-dialout-trunk:3] NoOp("SIP/31163-00002883", "TRUNK Dial failed due to CONGESTION HANGUPCAUSE: 31 - failing through to other trunks") in new stack
[Feb 9 08:36:42] VERBOSE[10472] pbx.c:     -- Executing [continue@macro-dialout-trunk:3] NoOp("SIP/31142-0000288d", "TRUNK Dial failed due to CONGESTION HANGUPCAUSE: 31 - failing through to other trunks") in new stack
[Feb 9 08:42:10] VERBOSE[10499] pbx.c:     -- Executing [continue@macro-dialout-trunk:3] NoOp("SIP/31161-00002897", "TRUNK Dial failed due to CONGESTION HANGUPCAUSE: 31 - failing through to other trunks") in new stack
[Feb 9 08:44:45] VERBOSE[10512] pbx.c:     -- Executing [continue@macro-dialout-trunk:3] NoOp("SIP/31131-0000289c", "TRUNK Dial failed due to CONGESTION HANGUPCAUSE: 31 - failing through to other trunks") in new stack
[Feb 9 08:49:55] VERBOSE[10523] pbx.c:     -- Executing [continue@macro-dialout-trunk:3] NoOp("SIP/31112-0000289f", "TRUNK Dial failed due to CONGESTION HANGUPCAUSE: 31 - failing through to other trunks") in new stack

Aquí se aprecia que el código de terminación de la llamada fue el 31. Si buscamos en Google encontraremos que el código 31 dice «Normal, unspecified», significando que la llamada terminó por causas normales que no fueron especificadas. Esto es normal de vez en cuando, pero tener tantos intentos fallidos en el mismo intervalo de tiempo me hizo investigar más.

Encontré los números que se marcaban y tomé mi línea analógica convencional y marqué a ellos. Los resultados fueron diferentes para los diferentes números:

  • «El número que marcó está fuera de servicio»
  • «El número que marcó está suspendido»
  • «El número que marcó no existe»
  • «El número celular que usted marcó no está disponible o se encuentra fuera del área de servicio»

Entonces no era problema que todos los canales estuvieran ocupados, sino que el carrier NO estaba regresándonos la causa correcta de terminación de la llamada para cada caso específico. Esto es sumamente importante, ya que en base al código de error obtenido sabes como debes retroalimentar a los usuarios para que reintenten pasados unos minutos o bien, que dejen de intentar llamar a un número imposible de localizar.

A pesar que trates de explicarle esto a los clientes, muchos no entienden que las líneas digitales se basan en códigos de error y no en grabaciones que escuchan en su línea al momento de marcar. Decir que todos los circuitos están ocupados normalmente es asociado con problemas de capacidad (piensan que hacen demasiadas llamadas simultáneas) o con un problema del conmutador, y acaban echándote la culpa a ti como proveedor del mismo.

Como el problema escalaba de lo que éramos capaces de ofrecer (ya que el enlace es provisto por el carrier, no por nosotros) no nos quedó de otra que levantar la incidencia. Esto fue desde noviembre 2011. Múltiples pruebas se tuvieron que hacer para demostrar a los ingenieros de soporte del carrier que el problema no venía del conmutador, sino de su enlace (o bien, de la interconexión de ellos con el destino al que se estaba marcando).

Tras 3 meses de idas y vueltas, reportes enviados y pruebas fallidas, antier me reportaron que por fin pudieron cumplirse pruebas exitosas del proyecto. El problema radicó en la interconexión entre carriers, no en la conexión de Asterisk.

Los ingenieros de soporte nos hicieron notar que gracias a la insistencia de nuestra parte el problema pudo detectarse e inclusive, se corrigió para todos los usuarios del mismo tipo de servicio. Inclusive la retroalimentación fue que muchos proveedores de conmutadores de telefonía convencional disfrazan los códigos de error recibidos para otorgarle al usuario respuestas aceptables en los problemas de los enlaces digitales. Sin embargo, Asterisk es de los pocos conmutadores con acceso total a la información (sin restricciones), por lo que pudimos meternos a hacer un debug intensivo del medio y pudimos refutar al carrier que el problema no venía de nuestro lado.

Sin acceso a la información que Asterisk entrega, nunca hubiéramos tenido las pruebas para acusar a quien tuvo la verdadera culpa del problema y hoy, seguiríamos igual que al principio.

Creo que la moraleja de esta historia es: nunca asuman que el proveedor grande siempre tiene la razón. Consigan pruebas, experimenten y evalúen sus resultados. Es muy probable que ustedes sean quienes puedan salir victoriosos de la contienda, solo infórmense bien de lo que ustedes saben que deberían estar recibiendo.

¡Suerte!

T1s ISDN PRI con el medio arriba pero caídos en servicios

2 Dic

Vicidial con 150 posiciones en San Juan, PR


Nos por la mañana nos desmadrugó un cliente que tenemos en Puerto Rico (en México estamos 2 atrasados con respecto de ellos), indicándonos que los agentes no podian sacar llamadas al exterior en ocasiones. Algunas veces podían marcando manualmente, otras no.

Como antecedente, el cliente tiene 8 T1s en ISDN PRI, dándole un total de 23*8=184 canales totales. De ese total de canales, tiene 10 reservados en los primeros 2 T1s para solo inbound, y lo demás es outbound libre, de manera que los agentes toman cualquiera de los canales que estén disponibles para marcar al exterior.

Los T1s de salida estaban agrupados en uno solo, el grupo 0 (cero), con lo cual yo mandaba la llamada así:

[codesyntax lang=»php»]

exten => _787ZXXXXXX,n,Dial(DAHDI/r0/${EXTEN})

[/codesyntax]

De esta manera, no tengo que preocuparme por ver por cual canal mandar la llamada, sino que en round robin se irá rotando por el total de canales disponibles para outbound. En teoría todo está bien, pero…

Al momento de hacer pruebas, efectivamente, algunos agentes en ocasiones no podian sacarlas. El sistema no les daba error, sino que se quedaba en vacio, sin que nada apareciera o se escuchara. Si colgábamos y volviamos a marcar el mismo número, el resultado era diferente y la llamada ya pasaba.

¿Qué podía estar pasando?

Dedicimos probar uno por uno los T1s. Sin embargo, dado que sus canales estaban todos agrupados en uno solo, no nos era posible enviar llamadas que se distinguieran por cada uno de ellos. La solución fue modificar el chan_dahdi.conf para que se viera así:

[codesyntax lang=»bash»]

;;;;;;;;;;;;;;;;;;;;;;;;;
;; Llamadas de outbound
;;;;;;;;;;;;;;;;;;;;;;;;;
switchtype=national
context=trunkinbound
group=0,21
echocancel=yes
faxdetect=incoming
signalling=pri_cpe
channel =>13-23
group=0,22
channel =>38-47
group=0,23
channel =>49-71
group=0,24
channel =>73-95
group=0,25
channel => 97-119
group=0,28
channel => 169-191

;;;;;;;;;;;;;;;;;;;;;;;;;
;; Llamadas de outbound - Marcacion especial
;;;;;;;;;;;;;;;;;;;;;;;;;
switchtype=national
context=trunkinbound
group=1
echocancel=yes
faxdetect=incoming
signalling=pri_cpe
group = 1,26
channel =>121-143
group = 1,27
channel => 145-167

;;;;;;;;;;;;;;;;;;;;;;;;;
;; Llamadas de inbound
;;;;;;;;;;;;;;;;;;;;;;;;;
switchtype=national
context=trunkinbound
group=9
echocancel=yes
faxdetect=incoming
signalling=pri_cpe
channel =>1-12,25-37

[/codesyntax]

Observando el primer bloque de llamadas de outbound, veremos que los canales ahora siguen estando agrupados en el 0, pero también lo separé y cree los grupos 21-27.  De esta manera, yo puedo escoger cuando marcar por cada uno de esos grupos y saber si el T1 está mal (recordemos que en señalización están perfectos porque no tienen alarmas, pero administrativamente la telefónica no le está dando servicio por alguno de ellos). La parte de las llamadas la resolví con esto dentro del extensions.conf:

[codesyntax lang=»bash»]

exten => _8Z787ZXXXXXX,1,Dial(DAHDI/r2${EXTEN:1:1}/${EXTEN:2});

[/codesyntax]

La idea es que marcando por ejemplo, 81 + 10 digitos estamos obligando a que la llamada salga por el T1 1. Si marcáramos con 82 saldría por el 2 y así sucesivamente. Esto le da la opción al administrador de hacer un debug y determinar si las llamadas por allí son efectivamente válidas.

Tras unos intentos de llamada fue posible notar que los T1s 3 y 5 no tenían salida a pesar de no estar alarmados. Como el formato de round robin se brinca aquellos canales que están alarmados, la solución sencilla fue desconectar físicamente esos T1s y reportarlos con la telefónica. Cundo le restauren el servicio, el administrador podrá conectarlos nuevamente y probarlos con 83 u 85 para comprobar que esos si sirven.

En este momento, el callcenter está operando correctamente y los agentes hacen llamadas de manera normal. Ahora solo resta a la telefónica resolver el problema para que todo esté al 100%.

¡Suerte!

Como agregar contextos personalizados en todos los servidores de un cluster con Vicidial

13 Oct

Hoy me di a la tarea de implementar un plan de llamadas personalizado en un cluster de Vicidial: mi cliente no quería que existiera la posibilidad de que los agentes marcaran manualmente desde su X-Lite, y al tratarse de un entorno de múltiples servidores, a la larga resultaría complicado mantener por separado cada uno de los archivos extensions.conf de los servidores.

¿Cuál es entonces la mejor manera para crear contextos de plan de llamadas que aparezcan en TODOS los servidores instalados en un cluster de Vicidial sin tener el problema de replicar manualmente los cambios?

La respuesta viene con las últimas versiones de Vici (2.2+) ya que bajo Admin -> System settings viene un espacio interesante donde podemos agregar planes de llamadas personalizados: el Custom Dialplan Entry.

Custom Dialplan Entry para Vicidial

Sin embargo, hay un problema, y es que todo lo colocado en esta caja se escribe dentro del contexto [vicidial-auto], por lo que si decidimos ingresar contextos por separado, romperiamos la funcionalidad del plan de llamadas automático de Vici, pero el truco es más sencillo de lo que se cree. Solo tenemos que iniciar y terminar nuestro bloque con las siguientes líneas:

[codesyntax lang=»bash»]

include => vicidial-auto2

; Este es mi contexto personalizado
[agentes]
exten => _ZXXX,1,Dial(SIP/${EXTEN})
; Fin de mi contexto personalizado

[vicidial-auto2]

[/codesyntax]

¿Qué logramos hacer con esto? Hacemos que nuestro cluster genere todos los contextos personalizados que metamos en medio de nuestras lineas, pero además, no rompemos la funcionalidad de Vici porque la línea de include => vicidial-auto2 hace que la inclusión del contexto [vicidial-auto2] sea transparente, de manera que no rompemos ninguna de las funcionalidades del sistema, y evitamos tener que administrar una linea de comandos para que la exportación de la configuración sea más transparente.

Este truco me sacó de un problema que sé que a la larga, se habría perdido el control de la administración tarde o temprano.

¡Suerte!

Recuperar la contraseña de FreePBX

3 Oct

Muchos han pedido un tutorial de como recuperar la contraseña de FreePBX, lo cual es bastante sencillo una vez que tienes la contraseña de root de Linux. Asumiendo esto, el proceso a seguir es bastante fácil, solo hay que cambiar los passwords desde MySQL. Aquí pongo los comandos directos para hacerlo desde el CLI de Linux (estamos asumiendo que el password de root de MySQL es eLaStIx.2oo7)

Si tienes FreePBX 2.5 o inferior:

[codesyntax lang=»bash»]
echo «UPDATE asterisk.ampusers SET password=’minuevopass’ WHERE username = ‘admin'» | mysql -peLaStIx.2oo7 asterisk
[/codesyntax]

Si tienes FreePBX 2.6 o superior

[codesyntax lang=»bash»]

echo "UPDATE asterisk.ampusers SET password_sha1=SHA1('minuevopass') WHERE username = 'admin'" | mysql -peLaStIx.2oo7 asterisk

[/codesyntax]

Con FreePBX 2.6+ la contraseña se guarda como hash SHA1, por lo que no es posible recuperarla. Sin embargo, en versiones anteriores se guardaba en texto plano, por lo que un simple SELECT nos revelaria cual era la contraseña que teniamos.

OJO: obviamente es necesario cambiar «minuevopass» por lo que queramos que sea nuestra nueva contraseña

¡Suerte!

6 razones por las cuales tu campaña en Vicidial podría no funcionar

28 Sep

Como se ha visto, recientemente hemos tenido mucho movimiento sobre Vicidial, que es una suite open source para instalar un callcenter completo sobre Linux. Pues bien, es bastante común que dado lo complejo que resulta este sistema cometamos errores y que por lo tanto nuestras campañas de marcación predictiva no saquen llamadas al exterior. Aquí recopilo algunos de los errores más comunes al momento de hacer marcación predictiva hacia el exterior:

  • Las campañas tienen el horario incorrecto. Muchas veces, las pruebas las hacemos en las noches y movemos la hora de las llamadas para entender por que no salen. Primer paso: asegurémonos de que la hora de la campaña sea la correcta y que estemos haciendo pruebas dentro del horario REAL en que se supone que nuestras campañas deben de correr.
  • No hay leads disponibles para marcar. Asegurémonos que las listas que tenemos dadas de alta para nuestra campaña tengan leads con los status de marcación válidos. Normalmente, marcamos a los NEW (nuevos leads), NA (No Answer) y B (Busy). Si nuestra lista está llena de leads que no tienen estos status, no se marcará hacia ellos. Agreguemos los nuevos status que queramos dentro de la campaña para ser válidos de remarcarles o bien, importemos nuevos leads para reintentar la operación.
  • No hay leads en el hopper. Si mandamos llamadas demasiado rápido o tenemos muchos agentes, lo más probable es que nos agotemos el hopper realmente rápido. Lo ideal es que nuestro hopper level (a nivel de campaña) esté ubicado en al menos 2.5 veces el número de agentes que podemos tener en línea en un momento dado. Este error es fácil de encontrar ya que nos aparecen indicaciones al hacer login como agente, asi que no debería ser problema localizar de que se trata.
  • Las llamadas no están saliendo a pesar de tener agentes en línea. Esto me pasó recientemente: todos los problemas de arriba habían sido verificados, pero había 5 agentes en línea y ninguno recibía llamadas. El problema fue de que tenía yo creada una campaña de marcación automática con agentes remotos (para enviar mensajes pre-grabados) y esto ocasionó que nos termináramos la cantidad de troncales disponibles para marcar al exterior (aunque nunca se usaron). Moraleja: asegúrate que bajo System Settings, el valor de Max Vicidial Trunks sea más grande que la cantidad total de agentes que tengas en un momento dado, y en caso de que así sea, asegúrate de no tener agentes remotos activos que tengan múltiples lineas de salida activadas. Al parecer, Vicidial reserva lineas aún para los agentes remotos que no las están usando.
  • Las llamadas no enlazan: dan un timeout y la interfaz de agente se queda esperando en estado «ringing». Comúnmente es ocasionado por enlaces digitales que NO son ISDN, como R2 modificado. Algunos proveedores dan mensajes grabados en early media audio dando grabaciones como «el número que marcó no existe». Normalmente, una persona escucharía esto y sabría que hacer, pero un sistema piensa que la llamada nunca se contestó y por lo tanto, ocurre un timeout porque 1) nunca obtuvimos ring y 2) nunca nos contestaron. La única solución es cambiar de enlace o cambiar a marcación manual, de manera que nuestros agentes puedan catalogar por ellos mismos el estado de las llamadas.
  • Las llamadas se cortan a los pocos segundos y nunca se enlazan a los agentes. Descubrí que si en la marcación automática haces un ANSWER antes de enviar un DIAL (es decir, sin un ringing de por medio), Vicidial nunca te enlaza las llamadas y te las marca como NA (No Answer). Lo correcto es que siempre debe haber un ringing antes de que la llamada sea contestada. Con eso evitarás que se marque pero nunca comunique a los agentes.

Como siempre, habrá muchas otras cosas que puedan pasar, pero en este caso estas son las más comunes. Conforme nuestra experiencia vaya aumentando, iremos ampliando la lista.

¡Suerte!

Como reiniciar masivamente todos los dispositivos Cisco SPA de tu red

27 Sep

El día de ayer publicamos un mini tutorial de como reiniciar masivamente todos los teléfonos Aastra de nuestra red. Hoy publicamos el equivalente aplicable para todos los teléfonos Cisco SPA (esto aplica también para la vieja gama de Linksys/Sipura).

El código es aún más sencillo que el de ayer:

[codesyntax lang=»php»]

#!/bin/bash
RED=192.168.1.1/24
echo "Escaneando $RED ..... "
for IP in `nmap -sP -v $RED | grep "appears to be up" | cut -d' ' -f 2`
do
   wget -qT 1 --no-cache http://$IP/admin/reboot -O - > /dev/null
done

[/codesyntax]

Con un poco de ingenio, podemos mezclar ambos scripts para que en caso de tener mezcla de teléfonos, reiniciemos todo lo que nos encontremos.

¡Suerte!

Como reiniciar masivamente los teléfonos Aastra de tu red

26 Sep

Recientemente nos topamos con la necesidad de resetear cerca de 200 teléfonos Aastra en una misma red. Pudimos haber esperado a que los teléfonos comenzaran a registrarse solos, pero debido a que era un soporte de emergencia, utilizamos este script:

[codesyntax lang=»bash»]

#!/bin/bash
USER=admin
PASS=22222
RED=192.168.1.1/24
echo "Escaneando $RED ..... "
for IP in `nmap -sP -v $RED | grep "appears to be up" | cut -d' ' -f 2`
do
   wget -qT 1 --no-cache --http-user=$USER --http-passwd=$PASS http://$IP/logout.html -O - > /dev/null
   wget -qT 1 --no-cache --http-user=$USER --http-passwd=$PASS http://$IP/sysinfo.html -O - > /dev/null

   # Reset
   echo Reiniciando $IP
   wget -qT 1 --no-cache --post-data=resetOption=0 --http-user=$USER --http-passwd=$PASS http://$IP/reset.html -O - >/dev/null
done

[/codesyntax]

Lo que éste hace es escanear la red, abrir la interfaz web de todos los teléfonos, accesa con el usuario y contraseña default (admin/2222) y una vez adentro ingresa al menú Reset y posteriormente acciona el reseteo del teléfono. Para hacer uso de este script es necesario hacerlo ejecutable (chmod 755) y cambiar la variable de RED para que concida con la red que queremos resetear.

¡Suerte!