Asterisk: baneando IPs “peligrosas” de por paises

Hoy he encontrado una página muy interesante donde se reportan bloques de IP que pueden ser utilizados para realizar ataques. A la hora de securizar nuestro Asterisk, tener estos bloques de IPs denegados, nos ayudará mucho a mitigar malas experiencias, como por ejemplo, fraudes en llamadas.

Mi consejo es siempre banear todas las IPs excepto aquellas que queramos utilizar, conociendo a nuestros clientes, sin embargo, en algunos casos esto no puede ser, y hay que tener nuestro Asterisk abierto a todo el mundo.

¿A todo el mundo? Bueno, a casi todo el mundo. En este post explicaré como poner en funcionamiento un script que he encontrado junto a fail2ban (herramienta que no queremos que se deshabilite).

Este script que he encontrado en http://www.lowendguide.com/ se nutre de la base de datos de http://www.ipdeny.com, donde se pueden encontrar “algunas” (muchas) IPs que no son deseadas ni deseables, y desde las cuales se realizan mucho ataques. Estas están almacenadas por países.

Script:

Este script lo que hace es simplemente conectarse a la página, bajarse un listado de IPs de los países que queramos, y proceder a añadirlas en el IPTables de nuestra máquina. Sí, efectivamente, deberemos tener instalado IPTables en nuestro servidor para poder utilizar dicho script.

Una vez creado este script, el cual tenéis pegado en el siguiente apartado, lo que haremos es crear un fichero, con permisos de ejecución en nuestra máquina e insertar el siguiente código en bash:

#!/bin/bash
### Block all traffic from AFGHANISTAN (af) and CHINA (CN). Use ISO code ###
ISO="af cn"
 
### Set PATH ###
IPT=/sbin/iptables
WGET=/usr/bin/wget
EGREP=/bin/egrep
 
### No editing below ###
SPAMLIST="countrydrop"
ZONEROOT="/root/iptables"
DLROOT="http://www.ipdeny.com/ipblocks/data/countries"
 
cleanOldRules(){
$IPT -F
$IPT -X
$IPT -t nat -F
$IPT -t nat -X
$IPT -t mangle -F
$IPT -t mangle -X
$IPT -P INPUT ACCEPT
$IPT -P OUTPUT ACCEPT
$IPT -P FORWARD ACCEPT
}
 
# create a dir
[ ! -d $ZONEROOT ] && /bin/mkdir -p $ZONEROOT
 
# clean old rules
cleanOldRules
 
# create a new iptables list
$IPT -N $SPAMLIST
 
for c in $ISO
do
 # local zone file
 tDB=$ZONEROOT/$c.zone
 
 # get fresh zone file
 $WGET -O $tDB $DLROOT/$c.zone
 
 # country specific log message
 SPAMDROPMSG="$c Country Drop"
 
 # get 
 BADIPS=$(egrep -v "^#|^$" $tDB)
 for ipblock in $BADIPS
 do
 $IPT -A $SPAMLIST -s $ipblock -j LOG --log-prefix "$SPAMDROPMSG"
 $IPT -A $SPAMLIST -s $ipblock -j DROP
 done
done
 
# Drop everything 
$IPT -I INPUT -j $SPAMLIST
$IPT -I OUTPUT -j $SPAMLIST
$IPT -I FORWARD -j $SPAMLIST
 
# call your other iptable script
# /path/to/other/iptables.sh
 
exit 0

Si os fijáis bien, en la segunda línea del script se puede indicar entre las comillas los países que queremos que se baneen.:

### Block all traffic from AFGHANISTAN (af) and CHINA (CN). Use ISO code ###
ISO="af cn"

Si queremos banear las no deseadas de España, pondremos: “es” entre las comillas.

Una vez realizado esto, ejecutamos el script y a esperar. ¡Ojo! Este script siempre borra todo lo que tengáis en el IPTables, dado que ejecuta una función definida dentro del mismo llamada “cleanOldRules” la cual hace un flush de todas las reglas existentes.

Una vez realizado esto, y para mantener nuestro Fail2Ban trabajando como es de recibo, lo que os aconsejo es que procedáis a realizar un:

/etc/init.d/iptables reload

Con esto volveremos a cargar las chains de reglas del IPtables.

Depués de utilizar este script, y hacer un Word count de IPtables, pues me han aparecido un todal de 57692 reglas que banean (casi nada, y eso que comenté la parte de LOG…)

root@VOIP:/etc/asterisk# iptables -nL | wc -l
57692
root@VOIP:/etc/asterisk#

Mi consejo es que para ver que hace iptables de ahora en adelante, utilicéis un head (y a poder ser que os creéis un alias en la consola http://www.thegeekstuff.com/2010/04/unix-bash-alias-examples/). Las reglas se añaden en una cadena llamada “countrydrop”:

root@VOIP:/etc/asterisk# iptables -nL | head -n 20

Chain INPUT (policy ACCEPT)
target prot opt source destination
fail2ban-ASTERISK-UDP all -- 0.0.0.0/0 0.0.0.0/0
fail2ban-ASTERISK-TCP all -- 0.0.0.0/0 0.0.0.0/0
fail2ban-ssh tcp -- 0.0.0.0/0 0.0.0.0/0
countrydrop all -- 0.0.0.0/0 0.0.0.0/0

Chain FORWARD (policy ACCEPT)
target prot opt source destination
countrydrop all -- 0.0.0.0/0 0.0.0.0/0

Chain OUTPUT (policy ACCEPT)
target prot opt source destination
countrydrop all -- 0.0.0.0/0 0.0.0.0/0

Chain countrydrop (3 references)
target prot opt source destination
DROP all -- 27.116.56.0/22 0.0.0.0/0
DROP all -- 43.231.131.0/24 0.0.0.0/0
DROP all -- 43.249.40.0/22 0.0.0.0/0

Luego para no tener que repetir el proceso cada vez que se reinicie la máquina, haré un:

root@VOIP:/etc/asterisk# /etc/init.d/iptables-persistent save

¡Espero que este post sea de utilidad!

 

Referencias:

http://www.lowendguide.com/3/networking/block-an-entire-country-with-iptables-2/

http://www.ipdeny.com/ipblocks/data/countries

http://jonathanmanning.com/2012/01/17/how-to-iptables-firewall-configuration-for-sipvoip-on-centos-rackspace-cloud/

QoS sobre nuestras comunicaciones VoIP (SIP y RTP)

Cuando etiquetamos tráfico con diferentes priorirdades, existen dos modos de hacerlo, a nivel de protocolo IP (ToS) o a nivel de VLAN (802.1p). En este post vamos a ocuparnos de la primera parte, de la que se encarga de realizar diferenciación a nivel de IP (ToS).

A pesar de que en la practica presentada vamos a trabajar etiquetando todo el tráfico de VoIP entre dos redes, es necesario comentar que lo que queremos tratar con más alta prioridad no es el tráfico SIP (señalización) o el que se encuentre entre dos redes, sino sólo el RTP (paquetes de voz) que es el que lleva la información que una vez iniciada la conversación nos interesará más.

 

Diferenciación a nivel IP: DSCP (ToS)

El ToS (Type Of Service) es un campo que existe en la cabecera del protocolo IPV4 el cual se ha definido en diferentes RFCs. Es un campo de 6 bits, el cual indica a los routers que a la hora de enrutar los paquetes deben de hacerlo con mayor prioridad que el resto.

En la practica, nunca se ha aplicado a nivel extendido, pero en entornos que controlemos nosotros, es decir, en nuestra red, podemos trabajar sin problema con este parámetro.

Cuanto mayor sea el valor de este campo, mejor. Es decir, cuanto mayor sea más prioridad se le va a dar al paquete. La siguiente tabla se puede encontrar en Wikipedia. En nuestro caso, y como lo que queremos es dar prioridad a tráfico de VoIP vamos a diferenciar los datos RTP de nuestras comunicaciones.

DSCP Name DS Field Value (Dec) IP Precedence (Description)
CS0 0 0 : Best Effort
CS1,AF11-13 8,10,12,14 1 :Priority
CS2,AF21-23 16,18,20,22 2 :Immediate
CS3,AF31-33 24,26,28,30 3 :Flash – mainly used for voice signaling
CS4,AF41-43 32,34,36,38 4 :Flash Override
CS5,EF 40,46 5 :Critical – mainly used for voice RTP
CS6 48 6 :Internet
CS7 56 7 :Network

 

Diferenciación a nivel MAC: 802.1p

Esta técnica consiste, conocica como CoS, es un campo que se engloba dentro del las etiquetas del protocolo VLAN 802.1Q. Consiste en dar un valor a un campo de 3 bits llamado PCP. Su valor va entre 0 y 7 a nivel de prioridad. En la siguiente tabla de Wikipedia se puede ver los diferentes valores y acrónimos que se utilizan para este campo. Paara nuestro caso, el de tráfico VoIP, deberemos de utilizar el nivel 5, dejando los dos superiores a capas de management e internetwork.

PCP Priority Acronym Traffic types
1 0 (lowest) BK Background
0 1 BE Best Effort
2 2 EE Excellent Effort
3 3 CA Critical Applications
4 4 VI Video, < 100 ms latency and jitter
5 5 VO Voice, < 10 ms latency and jitter
6 6 IC Internetwork Control
7 7 (highest) NC Network Control

Es de importancia vital entender que el estandard 802.1p se encuentra intimamente relacionado con los 802.1d y 802.1q.

Implementando DSCP en nuestra red VoIP:

Tal y como hemos comentado anteriormente, vamos a realizar una aproximación. En nuestro caso lo que vamos a etiquetar es el tráfico saliente, para que llegue correctamente identificado a su destino, así como a los saltos intermedios. No tiene sentido etiquetar el tráfico en destino, dado que ya ha recorrido del paquete ya se ha realizado, con el riesgo de que haya sufrido congestión o pérdidas.

En nuestro Asterisk procedemos a realizar un etiquetado de tráfico a nivel de DSCP a través de iptables añadiendo las siguientes reglas con mangle. Siguiendo la tabla al campo DSCP le vamos a asignar el valor EF (que en decimal es 46, y en hexadecimal corresponde a 2E).

iptables -A OUTPUT -t mangle -p udp -m udp --sport 5060 -j DSCP --set-dscp 0x2e
iptables -A OUTPUT -t mangle -p udp -m udp --dport 5060 -j DSCP --set-dscp 0x2e
iptables -A OUTPUT -t mangle -p udp -m udp --sport 10000:20000 -j DSCP --set-dscp 0x2e
iptables -A OUTPUT -t mangle -p udp -m udp --dport 10000:20000 -j DSCP --set-dscp 0x2e

Una vez aplicado esto en nuestro iptables, si hacemos un tcpdump o ngrep, veremos como el tráfico que se envía a con puertos de origen iguales a los que hemos definido (protocolo UDP) aparecen con DSCP EF.

Routers Cisco:

A continuación vamos a configurar las diferentes políticas en nuestros routers Ciscos para que trabajen con DSCP, etiquetando todo el tráfico que entre con un destino determinado.

Configuramos un object-group para identificar todo el tráfico de voz que vamos a enviar:

object-group service voipservice 
 udp eq 5060
 udp gt 10000
 udp lt 20000

Después creamos las ACLs donde identificamos este tráfico. Para nuestro caso, vamos a tratar el tráfico que tiene como origen 192.168.3.0/24 y destino 192.168.1.0/24, pero podríamos haber puesto “any any” para cualquier tipo de tráfico que cumpliese el object-group. El hecho de realizar estos ACLs se realiza para aplicar después a los class-maps:

access-list 100 permit object-group voipservice 192.168.1.0 0.0.0.255 192.168.3.0 0.0.0.255

Creamos un class-map utilizando esta ACL para así poder tener nuestro tráfico clasificado dentro de nuestro router:

class-map match-any voip
 description VoIP-Traffic
 match access-group 100

Y finalmente la aplicamos a este tráfico una acción con policy-map. Es decir, ya lo tenemos identificado dentro de un class-map, y ahora le decimos que lo etiquete como EF en su campo DSCP.

policy-map voipdscppolicy
 description VoIP-Traffic-192168003
 class voip
  set ip dscp ef

Una vez tenemos esto ya configurado, aplicamos este policy-map en las interfaces de entrada. En nuestro caso es una interfaz que va conecta a la LAN del cliente, pero podría ser, perfectamente, una VLAN.

interface FastEthernet0/0
 description LANCLIENTE
 ip address 192.168.3.1 255.255.255.0
 !
 service-policy input voipdscppolicy

Y a generar tráfico y ver qué pasa. En mi caso, a la ACL he añadido una regla para que los ICMPs también los etiquete (he utilizado GNS3 para estas simulaciones).

CapturaTraficoEF

Referencias:

http://en.wikipedia.org/wiki/Type_of_service

http://en.wikipedia.org/wiki/IEEE_P802.1p

Kamailio – Asterisk Realtime: Voicemails para nuestros usuarios de Kamailio (Parte 2)

En la parte dos, vamos a hacer un script para que cuando un usuario pulse un código determinado, se haga un dial contra nuestro Kamailio, y entre en un menú para activar o desactivar el buzón de voz, autenticandose por password.

Básicamente deberemos de configurar una ruta para que las llamadas con un determinado código vayan a nuestro Asterisk Realtime, que hemos configurado en Parte 1, y allí dentro hacer unas rutinas para escribir y borrar en el database en que correrá en el Asterisk Realtime.

En el caso que nos ocupa, hemos elegido los siguientes códigos:

90: Activar Voicemail

91: Desactvar voicemail

Bien, ahora vamos a ponernos a la configuración. En Kamailio simplemente hemos de hacer una ruta para que dentro de route[PSTN] se reenvien estas llamadas contra el TOVOICEMAIL cuando hagamos un request de 90 o 91:

if($rU=~"^(9[0-1])"){
   xlog("*****DEBUGTONI: REDIRECTING TO VOICEMAIL\n");
   route(TOVOICEMAIL);
   exit;
 }

Ahora nos meteremos en Asterisk . Lo primero que haremos es configurar el odbc para que desde nuestro dialplan podamos acceder al mysql donde tenemos cargada la configuración de nuestros voicemail y sipusers para poder modificarla.

root@vm-server-001:~# vim /etc/odbc.ini
[MySQL-asterisk]
Description = MySQL Asterisk database
Trace = Off
TraceFile = stderr
Driver = MySQL
SERVER = localhost
USER = asterisk
PASSWORD = Passw0rdMysqL!
PORT = 3306
DATABASE = asterisk

Una vez creado el conector para realizar las conexiones de mysql contra esta base de datos, procederemos a definir las queries que utilizaremos. En este caso, vamos a definir dos bien diferenciadas: activar voicemail (VOICEMAILACT) y desactivar (VOICEMAILACTDEACT) voicemail.

root@vm-server-001:~# vim /etc/asterisk/func_odbc.conf

[VOICEMAILACT]
dsn=asterisk
prefix=FO
readsql=SELECT mailbox FROM voicemail WHERE mailbox='${ARG1}'
writesql=INSERT INTO voicemail (context,mailbox,password,email) VALUES ('${ARG1}','${ARG2}','${ARG3}','${ARG4}')

[VOICEMAILACTDEACT]
dsn=asterisk
prefix=FO
readsql=SELECT mailbox FROM voicemail WHERE mailbox='${ARG1}'
writesql=DELETE FROM voicemail WHERE mailbox='${ARG1}'

Para que nuestro Asterisk vea que tenemos estas funciones, deberemos recargar el modulo de res_odbc y el fun_odbc, donde se cargará el conector y las funciones creadas respectivamente. En el output del cli de Asterisk veremos que aparecen las funciones creadas.

vm-server-001*CLI> module reload res_odbc.so
vm-server-001*CLI> module reload func_odbc.so

vm-server-001*CLI> odbc show all

ODBC DSN Settings
-----------------

 Name: asterisk
 DSN: MySQL-asterisk
 Last connection attempt: 1970-01-01 00:00:00
 Pooled: No
 Connected: Yes

vm-server-001*CLI> 

Finalmente, simplemente tenemos que definir en el extensions.conf de Asterisk qué debemos de hacer con las llamadas, es decir, ver si estamos activando o desactivando el voicemail.

Como se puede ver, lo que vamos a analizar es el campo from del paquete SIP, y nos vamos a quedar con la parte  “Uri Username” que está entre los dos puntos del sip: y el @ del dominio. En este caso, la Requested URI no nos aporta información sobre el usuario, dado que todos nuestros usuarios marcarán 90 o 91.

exten => 90,1,NoOp(**Desactivando VM**)
same => n,Set(tmp=${SIP_HEADER(From)})
same => n,Set(tmp=${CUT(tmp,@,1)})
same => n,Set(tmp=${CUT(tmp,:,2)})
same => n,Set(exists=$[FO_VOICEMAILACTDEACT(${tmp})])
same => n,GoToIf($["${exists}"="${tmp}"]?ok:error)
same => n(ok),Set(FO_VOICEMAILACTDEACT(${tmp})=test)
same => n(ok),PlayBack(voice-mail-system&de-activated)
same => n(ok),Hangup()
same => n(error),NoOp(**Error deactivatingVM ${test})
same => n(error),PlayBack(an-error-has-occured)
same => n(error),Hangup()
same => n,Hangup

exten => 91,1,NoOp(**Activando VM**)
same => n,Set(tmp=${SIP_HEADER(From)})
same => n,Set(tmp=${CUT(tmp,@,1)})
same => n,Set(tmp=${CUT(tmp,:,2)})
same => n,Set(exists=$[FO_VOICEMAILACTDEACT(${tmp})])
same => n,GoToIf($["${exists}"="${tmp}"]?error:ok)
same => n(ok),Set(FO_VOICEMAILACT("default",${tmp},"9685324","tibanezlujan@gmail.com")=test)
same => n(ok),NoOp(${res})
same => n(ok),Playback(voice-mail-system&activated)
same => n(ok),Hangup()
same => n(error),NoOp(**Error deactivatingVM ${test})
same => n(error),PlayBack(an-error-has-occured)
same => n(error),Hangup()
same => n,Hangup

Por otro lado, en el caso de activación he puesto a mano la password y el correo (es una prueba de concepto) pero simplemente sería necesario definir un database extra en nuestro mysql server y consultar esta variable, igual que lo hemos hecho con la variable de voicemail.

Es interesante ver que hemos definido dos lineas antes de añadir o eliminar el voicemail donde se mira que exista al voicemail, dado que si existe, no dejaremos que se cree de nuevo, y si no existe, no permitiremos que se elimine dicho registro.

Importante: Tal y como vimos en Parte 1, en mi caso, antes de enviar a Kamailio es muy importante que hayamos substituido el from por el DDI del cliente, para asociar la el número de buzón a este DDI y no al username.

Podríamos utilizar el Voicemail con usuario, pero luego a la hora de decir que la extensión no está disponible, no se reproducirían los dígitos, y nuestro archivo extensions.conf debería de ser mucho más complejo a la hora de mapear expresiones regulares, de ahí que haya preferido trabajar con el DDI del cliente:

 -- Executing [90@from-kamailio:3] Set("SIP/sipproxy001-00000015", "tmp="victor-voip002" <sip:victor@voip002.netvoip.no-ip.org>;tag=a3jo6lz5iz") in new stack

Al fin y al cabo,si alguien llama desde el exterior, siempre llamará al DDI y no al sipUsername, de ahí que también esto sea importante tenerlo configurado así. En cualquier caso, simplemente comentar que nosotros desde Kamailio lo hemos enviado con el número del aliases, así que es pro este motivo que en Asterisk desmontamos el paquete SIP para poder quedarnos con la parte del fromUsername.

¡Espero que os sea de utilidad!

Kamailio – Asterisk Realtime: Voicemails para nuestros usuarios de Kamailio (Parte 1)

A continuación, lo que vamos a proceder a hacer es la integración de un Asterisk en realtime contra un Kamailio (el que hemos estado montando en posts anteriores) con la idea de poder ofrecer servicio de voicemail cuando el usuario esté ocupado y/o no se encuentre registrado en nuestro sistema (por algún corte en su linea IP, por ejemplo).

Al tratarse de un escenario completo, lo hemos dividido en dos partes, para ir poco a poco, y no hacer un post demasiado largo: La Parte 1 (esta que estás leyendo) consiste en poder dejar mensajes y que se envien al correo, mientras que en la Parte 2 configuraremos que los usuarios puedan activar y/o desactivar el servicio a través del mismo Asterisk.

Vamos a instalar un Asterisk en Realtime, para ello utilizaremos los repositorios de debian de asterisk.org. Así que lo primero es añadir el repositorio y hacer un update:

root@vm-server-001:~# add-apt-repository "deb http://packages.asterisk.org/deb `lsb_release -cs` main"

root@vm-server-001:~# apt-get update

Sin rompernos demasiado la cabeza, procedemos a realizar una instalación del Asterisk a pelo (muchos diran que es poco eficiente, pero al fin y al cabo es lo más rápido):

root@vm-server-001:~# apt-get install asterisk

Ahora mismo, la versión que está disponible es la de Asterisk11, tal y como podemos ver si nos conectamos a su consola:

root@vm-server-001:~# asterisk -rv
Asterisk 11.11.0~dfsg-2ubuntu1, Copyright (C) 1999 - 2013 Digium, Inc. and others.
Created by Mark Spencer <markster@digium.com>
Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.
[...]

Al tratarse de una instalación de Asterisk11 en Realtime, necesitaremos una base de datos para conectarnos y aguantar allí la configuración de nuestra PBX y nuestros voicemails, así que procedemos a la instalación de los paquetes necesarios, así como de ODBC para tratar con los drivers/librerias de mysql:

root@vm-server-001:~#apt-get install mysql-server

root@vm-server-001:~#apt-get install libmysqlclient-dev

root@vm-server-001:~#apt-get install unixodbc-dev

root@vm-server-001:~#apt-get install libmyodbc

Lo siguiente que tenemos que hacer, y esto lo he consultado en alguna página de las que tenemos en las referencias, es entrar en el mysql y crear el database para nuestro Asterisk. Para ello, definimos las tablas mysql para Asterisk dentro de un archivo llamado mysql_asterisk.sql (hacer copy paste de lo siguiente dentro de este archivo que creamos llamado mysq_asterisk.sql):

CREATE DATABASE asterisk;
 
USE asterisk;
 
GRANT ALL ON asterisk.* TO asterisk@localhost IDENTIFIED BY 'asterisk_password';
 
DROP TABLE IF EXISTS sipusers;
CREATE TABLE `sipusers` (
     `id` INT(11) NOT NULL AUTO_INCREMENT,
      `name` VARCHAR(10) NOT NULL,
      `ipaddr` VARCHAR(15) DEFAULT NULL,
      `port` INT(5) DEFAULT NULL,
      `regseconds` INT(11) DEFAULT NULL,
      `defaultuser` VARCHAR(10) DEFAULT NULL,
      `fullcontact` VARCHAR(35) DEFAULT NULL,
      `regserver` VARCHAR(20) DEFAULT NULL,
      `useragent` VARCHAR(20) DEFAULT NULL,
      `lastms` INT(11) DEFAULT NULL,
      `host` VARCHAR(40) DEFAULT NULL,
      `type` enum('friend','user','peer') DEFAULT NULL,
      `context` VARCHAR(40) DEFAULT NULL,
      `permit` VARCHAR(40) DEFAULT NULL,
      `deny` VARCHAR(40) DEFAULT NULL,
      `secret` VARCHAR(40) DEFAULT NULL,
      `md5secret` VARCHAR(40) DEFAULT NULL,
      `remotesecret` VARCHAR(40) DEFAULT NULL,
      `transport` enum('udp','tcp','udp,tcp','tcp,udp') DEFAULT NULL,
      `dtmfmode` enum('rfc2833','info','shortinfo','inband','auto') DEFAULT NULL,
      `directmedia` enum('yes','no','nonat','update') DEFAULT NULL,
      `nat` enum('yes','no','never','route') DEFAULT NULL,
      `callgroup` VARCHAR(40) DEFAULT NULL,
      `pickupgroup` VARCHAR(40) DEFAULT NULL,
      `language` VARCHAR(40) DEFAULT NULL,
      `disallow` VARCHAR(40) DEFAULT NULL,
      `allow` VARCHAR(40) DEFAULT NULL,
      `insecure` VARCHAR(40) DEFAULT NULL,
      `trustrpid` enum('yes','no') DEFAULT NULL,
      `progressinband` enum('yes','no','never') DEFAULT NULL,
      `promiscredir` enum('yes','no') DEFAULT NULL,
      `useclientcode` enum('yes','no') DEFAULT NULL,
      `accountcode` VARCHAR(40) DEFAULT NULL,
      `setvar` VARCHAR(40) DEFAULT NULL,
      `callerid` VARCHAR(40) DEFAULT NULL,
      `amaflags` VARCHAR(40) DEFAULT NULL,
      `callcounter` enum('yes','no') DEFAULT NULL,
      `busylevel` INT(11) DEFAULT NULL,
      `allowoverlap` enum('yes','no') DEFAULT NULL,
      `allowsubscribe` enum('yes','no') DEFAULT NULL,
      `videosupport` enum('yes','no') DEFAULT NULL,
      `maxcallbitrate` INT(11) DEFAULT NULL,
      `rfc2833compensate` enum('yes','no') DEFAULT NULL,
      `mailbox` VARCHAR(40) DEFAULT NULL,
      `session-timers` enum('accept','refuse','originate') DEFAULT NULL,
      `session-expires` INT(11) DEFAULT NULL,
      `session-minse` INT(11) DEFAULT NULL,
      `session-refresher` enum('uac','uas') DEFAULT NULL,
      `t38pt_usertpsource` VARCHAR(40) DEFAULT NULL,
      `regexten` VARCHAR(40) DEFAULT NULL,
      `fromdomain` VARCHAR(40) DEFAULT NULL,
      `fromuser` VARCHAR(40) DEFAULT NULL,
      `qualify` VARCHAR(40) DEFAULT NULL,
      `defaultip` VARCHAR(40) DEFAULT NULL,
      `rtptimeout` INT(11) DEFAULT NULL,
      `rtpholdtimeout` INT(11) DEFAULT NULL,
      `sendrpid` enum('yes','no') DEFAULT NULL,
      `outboundproxy` VARCHAR(40) DEFAULT NULL,
      `callbackextension` VARCHAR(40) DEFAULT NULL,
      `timert1` INT(11) DEFAULT NULL,
      `timerb` INT(11) DEFAULT NULL,
      `qualifyfreq` INT(11) DEFAULT NULL,
      `constantssrc` enum('yes','no') DEFAULT NULL,
      `contactpermit` VARCHAR(40) DEFAULT NULL,
      `contactdeny` VARCHAR(40) DEFAULT NULL,
      `usereqphone` enum('yes','no') DEFAULT NULL,
      `textsupport` enum('yes','no') DEFAULT NULL,
      `faxdetect` enum('yes','no') DEFAULT NULL,
      `buggymwi` enum('yes','no') DEFAULT NULL,
      `auth` VARCHAR(40) DEFAULT NULL,
      `fullname` VARCHAR(40) DEFAULT NULL,
      `trunkname` VARCHAR(40) DEFAULT NULL,
      `cid_number` VARCHAR(40) DEFAULT NULL,
      `callingpres` enum('allowed_not_screened','allowed_passed_screen','allowed_failed_screen'
                         ,'allowed','prohib_not_screened','prohib_passed_screen','prohib_failed_screen'
                         ,'prohib') DEFAULT NULL,
      `mohinterpret` VARCHAR(40) DEFAULT NULL,
      `mohsuggest` VARCHAR(40) DEFAULT NULL,
      `parkinglot` VARCHAR(40) DEFAULT NULL,
      `hasvoicemail` enum('yes','no') DEFAULT NULL,
      `subscribemwi` enum('yes','no') DEFAULT NULL,
      `vmexten` VARCHAR(40) DEFAULT NULL,
      `autoframing` enum('yes','no') DEFAULT NULL,
      `rtpkeepalive` INT(11) DEFAULT NULL,
      `call-limit` INT(11) DEFAULT NULL,
      `g726nonstandard` enum('yes','no') DEFAULT NULL,
      `ignoresdpversion` enum('yes','no') DEFAULT NULL,
      `allowtransfer` enum('yes','no') DEFAULT NULL,
      `dynamic` enum('yes','no') DEFAULT NULL,
      `sippasswd` VARCHAR(80) DEFAULT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `name` (`name`),
      KEY `ipaddr` (`ipaddr`,`port`),
      KEY `host` (`host`,`port`)
) ENGINE=MyISAM;
 
 
DROP TABLE IF EXISTS sipregs;
CREATE TABLE `sipregs` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(80) NOT NULL DEFAULT '',
  `fullcontact` VARCHAR(80) NOT NULL DEFAULT '',
  `ipaddr` VARCHAR(45) DEFAULT NULL,
  `port` mediumint(5) UNSIGNED NOT NULL DEFAULT '0',
  `username` VARCHAR(80) NOT NULL DEFAULT '',
  `regserver` VARCHAR(100) DEFAULT NULL,
  `regseconds` INT(11) NOT NULL DEFAULT '0',
  `defaultuser` VARCHAR(80) NOT NULL DEFAULT '',
  `useragent` VARCHAR(20) DEFAULT NULL,
  `lastms` INT(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
);
 
 
DROP TABLE IF EXISTS voicemail;
CREATE TABLE voicemail (
	-- All of these column names are very specific, including "uniqueid".  Do not change them if you wish voicemail to work.
	uniqueid INT(5) NOT NULL AUTO_INCREMENT PRIMARY KEY,
	-- Mailbox context.
	context CHAR(80) NOT NULL DEFAULT 'default',
	-- Mailbox number.  Should be numeric.
	mailbox CHAR(80) NOT NULL,
	-- Must be numeric.  Negative if you don't want it to be changed from VoicemailMain
	password CHAR(80) NOT NULL,
	-- Used in email and for Directory app
	fullname CHAR(80),
	-- Email address (will get sound file if attach=yes)
	email CHAR(80),
	-- Email address (won't get sound file)
	pager CHAR(80),
	-- Attach sound file to email - YES/no
	attach CHAR(3),
	-- Which sound format to attach
	attachfmt CHAR(10),
	-- Send email from this address
	serveremail CHAR(80),
	-- Prompts in alternative language
	LANGUAGE CHAR(20),
	-- Alternative timezone, as defined in voicemail.conf
	tz CHAR(30),
	-- Delete voicemail from server after sending email notification - yes/NO
	deletevoicemail CHAR(3),
	-- Read back CallerID information during playback - yes/NO
	saycid CHAR(3),
	-- Allow user to send voicemail from within VoicemailMain - YES/no
	sendvoicemail CHAR(3),
	-- Listen to voicemail and approve before sending - yes/NO
	review CHAR(3),
	-- Warn user a temporary greeting exists - yes/NO
	tempgreetwarn CHAR(3),
	-- Allow '0' to jump out during greeting - yes/NO
	operator CHAR(3),
	-- Hear date/time of message within VoicemailMain - YES/no
	envelope CHAR(3),
	-- Hear length of message within VoicemailMain - yes/NO
	sayduration CHAR(3),
	-- Minimum duration in minutes to say
	saydurationm INT(3),
	-- Force new user to record name when entering voicemail - yes/NO
	forcename CHAR(3),
	-- Force new user to record greetings when entering voicemail - yes/NO
	forcegreetings CHAR(3),
	-- Context in which to dial extension for callback
	callback CHAR(80),
	-- Context in which to dial extension (from advanced menu)
	dialout CHAR(80),
	-- Context in which to execute 0 or * escape during greeting
	exitcontext CHAR(80),
	-- Maximum messages in a folder (100 if not specified)
	maxmsg INT(5),
	-- Increase DB gain on recorded message by this amount (0.0 means none)
	volgain DECIMAL(5,2),
	-- IMAP user for authentication (if using IMAP storage)
	imapuser VARCHAR(80),
	-- IMAP password for authentication (if using IMAP storage)
	imappassword VARCHAR(80),
	-- IMAP server location (if using IMAP storage)
	imapsever VARCHAR(80),
	-- IMAP port (if using IMAP storage)
	imapport VARCHAR(8),
	-- IMAP flags (if using IMAP storage)
	imapflags VARCHAR(80),
	stamp TIMESTAMP
);
 
DROP TABLE IF EXISTS voicemail_data;
CREATE TABLE voicemail_data (
	-- Path to the recording
	filename CHAR(255) NOT NULL PRIMARY KEY,
	-- Mailbox number (without context)
	origmailbox CHAR(80),
	-- Dialplan context
	context CHAR(80),
	-- Dialplan context, if voicemail was invoked from a macro
	macrocontext CHAR(80),
	-- Dialplan extension
	exten CHAR(80),
	-- Dialplan priority
	priority INT(5),
	-- Name of the channel, when message was left
	callerchan CHAR(80),
	-- CallerID on the channel, when message was left
	callerid CHAR(80),
	-- Contrary to the name, origdate is a full datetime, in localized format
	origdate CHAR(30),
	-- Same date as origdate, but in Unixtime
	origtime INT(11),
	-- Value of the channel variable VM_CATEGORY, if set
	category CHAR(30),
	-- Length of the message, in seconds
	duration INT(11)
);
DROP TABLE IF EXISTS voicemail_messages;
CREATE TABLE voicemail_messages (
	-- Logical directory
	dir CHAR(255),
	-- Message number within the logical directory
	msgnum INT(4),
	-- Dialplan context
	context CHAR(80),
	-- Dialplan context, if Voicemail was invoked from a macro
	macrocontext CHAR(80),
	-- CallerID, when the message was left
	callerid CHAR(80),
	-- Date when the message was left, in Unixtime
	origtime INT(11),
	-- Length of the message, in seconds
	duration INT(11),
	-- The recording itself
	recording BLOB,
	-- Text flags indicating urgency of the message
	flag CHAR(30),
	-- Value of channel variable VM_CATEGORY, if set
	category CHAR(30),
	-- Owner of the mailbox
	mailboxuser CHAR(30),
	-- Context of the owner of the mailbox
	mailboxcontext CHAR(30),
	-- Unique ID of the message,
	msg_id CHAR(40),
	PRIMARY KEY (dir, msgnum)
);

Y lo siguiente es simplemente volcarla en nuestro servidor de mysql a través del siguiente comando:

root@vm-server-001:~# mysql -u root -p < mysql_asterisk.sql
 Enter password:
root@vm-server-001:~#

Entramos dentro de nuestro servidor mysql y creamos usuario mysql para Asterisk, el cual en principio sólo debe de conectarse desde nuestro mismo equipo (localhost):

mysql> GRANT ALL ON asterisk.* to asterisk@localhost IDENTIFIED BY 'passw0rd!!';

Ahora procedemos a configurar el driver de mysql  a través de ODBC:

root@vm-server-001:~# vim /etc/odbcinst.ini

[MySQL]
Description = MySQL driver
Driver = libmyodbc.so
Setup = libodbcmyS.so
CPTimeout =
CPReuse =
UsageCount = 1

Y siguiendo con la configuración, procedemos a configurar el acceso a mysql para que el driver pueda acceder a las tablas creadas:

root@vm-server-001:~# vim /etc/odbc.ini

[MySQL-asterisk]
Description = MySQL Asterisk database
Trace = Off
TraceFile = stderr
Driver = MySQL
SERVER = localhost
USER = asterisk
PASSWORD = passw0rdDelMysql!!
PORT = 3306
DATABASE = asterisk

Lo siguiente, es definir a Astersisk para que utilice ODBC así que procedemos a editar el archivo de configuración, para ello vamos a /etc/asterisk/res_odbc.conf y editamos del modo siguiente:

root@vm-server-001:~# vim /etc/asterisk/res_odbc.conf

[asterisk] 
enabled => yes 
dsn => MySQL-asterisk 
username => asterisk 
password => passw0rd!! 
pre-connect => yes

Vamos a ver si funciona. ¿Cómo? Conectandonos a la consola de asterisk y haciendo un ‘sip show peers’. ¿Cual es mi resultado? Que no funciona… Así que nos toca mirar el log, y lo que nos damos cuenta es de que tenemos un error en la carga de módulos… Hay que indicarle a Asterisk para que cargue el mysql:

root@vm-server-001:~# vim /etc/asterisk/modules.conf

; Enable these if you want to configure Asterisk in a database
;
load => res_config_odbc.so
load => res_config_pgsql.so

Bien, una vez comprovado que todo nuestro Asterisk está arriba y funcionando a través de mysql, lo siguiente que debemos de hacer es modificar el enrutado de Kamailio para que envie las llamada ahí cuando “algo malo pase” (que no nos conteste el cliente o que esté ocupado), así que procedemos a leer nuestro kamailio.cfg y vemos que, efectivamente, hay un modulo preparado para ello!

#!define WITH_VOICEMAIL

Procedemos a ajustar los parámetros conforme nuestro servidor Asterisk:

#!ifdef WITH_VOICEMAIL
# VoiceMail Routing on offline, busy or no answer
#
# - by default Voicemail server IP is empty to avoid misrouting
voicemail.srv_ip = "92.127.133.213" desc "VoiceMail IP Address"
voicemail.srv_port = "5060" desc "VoiceMail Port"
#!endif

Pero claro, nosotros lo queremos customizado, es decir, vamos a modificar un poco el tema de la no respuesta, dado que en Kamailio trabajamos con usernames, pero nos gustaría en asterisk identificar a los clientes por su DID, así que añadimos la traducción, tal y como hemos hecho en posts anteriores. Así queda la ruta de TOVOICEMAIL:

 route[TOVOICEMAIL] {
#!ifdef WITH_VOICEMAIL
 if(!is_method("INVITE|SUBSCRIBE"))
 return;

 # check if VoiceMail server IP is defined
 if (strempty($sel(cfg_get.voicemail.srv_ip))) {
 xlog("SCRIPT: VoiceMail rotuing enabled but IP not defined\n");
 return;
 }
 if(is_method("INVITE")) {
 if($avp(oexten)==$null)
 return;

 # MODIFIED: Poner aquí el tema de que si se trata de un interno, poner claramente que no es el useragent
 # si no el DID al que se ha llamado. En Asterisk vamos a poner el DID como rquested URI para 
 # poder trabajar con ello.

 if(avp_db_query("select alias_username from dbaliases where username='$rU' and domain='$fd'","$avp(callerid)")){
 xlog("*****DEBUGTONI: Enviando llamada a Voicemail dado que cliente no responde o no disponible $avp(callerid) ****\n");
 $ru= "sip:"+$avp(callerid)+"@"+$sel(cfg_get.voicemail.srv_ip)
 + ":" + $sel(cfg_get.voicemail.srv_port);
 }
 else{
 $ru = "sip:" + $avp(oexten) + "@" + $sel(cfg_get.voicemail.srv_ip)
 + ":" + $sel(cfg_get.voicemail.srv_port);
 }
 } else {
 if($rU==$null)
 return;

 $ru = "sip:" + $rU + "@" + $sel(cfg_get.voicemail.srv_ip)
 + ":" + $sel(cfg_get.voicemail.srv_port);
 }

 route(RELAY);
 exit;
#!endif

 return;
}

Esto está genial, pero ojo! Recordemos que en mi caso lo primero que hago es mirar si está en el route[LOCATION] y si no, intentar en el route[PSTN], por ello, si llamo a un número que no existe en nuestro dbaliases, no pasará del route[LOCATION], y este me lo intente enviar a nuestro Asterisk (fail, yo lo que quiero es llamar fuera de mi dominio). Por esto tengo que pulir la configuración .

Para que las llamadas salientes sigan saliendo correctamente, sólo deberemos de enviar las llamadas cuando existan en nuestro dbaliases y no se encuentren en el location, así que en el route[LOCATION] debemos de insertar lo siguiente antes de enviar a route[TOVOICEMAIL].

 if(avp_db_query("select alias_username from dbaliases where username='$rU' and domain='$fd'")) { 
 route(TOVOICEMAIL);
 }

Resumiendo: Si no existe en el dbaliases quiere decir que el DID al que se llama no está gestionado por mi, con lo cual, seguro que no tengo voicemail para el, y lo que debo de hacer es enviarlo a mis carriers.

Luego vamos al dialplan de Asterisk y comenzamos a darle caña con la configuración, lo primero es definir en nuestro sip.conf el troncal para recibir llamadas de nuestro kamailio.

[fromsbc](!) ; a template
 dtmfmode=rfc2833
 context=from-kamailio
 type=peer
 directmedia=no

[codecs](!) ; a template for my preferred codecs
 disallow=all
 allow=alaw
 allow=ulaw
 allow=gsm

[aclserver](!)
 deny=0.0.0.0/0.0.0.0
 permit=92.127.0.0/16
 permit=172.16.0.0/16

[sipproxy001](fromsbc,codecs)
 host=92.127.133.214

Una vez vemos que entran las llamadas, lo siguiente es procesarlas. Para ello hemos creado un contexto llamado [from-kamailio] donde procesaremos estas llamadas y las enviaremos al voicemail:

[from-kamailio]

exten => _9XXXXXXXX,1,NoOp("Llamada entrante buscando Voicemail de TONI TELECOM para ${EXTEN}")
same => n,Voicemail(${EXTEN},u)
same => n,GoToIf($["${VMSTATUS}"=="FAILED"]?fail,1)
same => n,Hangup()

exten => fail,1,NoOp(*Client with out VM configured*)
same => n,PlayBack(number-not-answering&or&is-currently&on-busy&please-try-again-later&&tt-monkeys)
same => n,Hangup()

exten => 90,1,NoOp(**TODO EN PARTE 2: Desactivar VM**)
same => n,Hangup

exten => 91,1,NoOp(**TODO EN PARTE 2: Activar VM**)
same => n,Hangup

¡Importante también! Las voces las queremos en castellano, así que nos las bajaremos de http://voipnovatos.es (¡el amigo Alberto aún las tiene colgadas!):

root@vm-server-001:/usr/src# wget https://www.voipnovatos.es/voces1.2/asterisk-voces-es-v1-711a-voipnovatos.zip

unzip asterisk-voces-es-v1-711a-voipnovatos.zip

cp -rv es/ /usr/share/asterisk/sounds/es_custom

No nos olvidaremos de en el sip.conf seleccionar este dentro de su sección [general]:

language=es_custom

Y ya para acabar lo que vamos a hacer es insertar usuarios en voicemail para que nos envíe un correo electrónico cuando llegue la llamada. Como podéis ver, todos los números los he reedirijido contra mi correo personal, dado que estamos en modo testing:

INSERT INTO voicemail(context, mailbox, password, email) VALUES ('default', '930000000', '1234','tibanezlujan@gmail.com');
 INSERT INTO voicemail(context, mailbox, password, email) VALUES ('default', '930000001', '1234','tibanezlujan@gmail.com'); 
INSERT INTO voicemail(context, mailbox, password, email) VALUES ('default', '930000002', '1234','tibanezlujan@gmail.com');
INSERT INTO voicemail(context, mailbox, password, email) VALUES ('default', '930000003', '1234','tibanezlujan@gmail.com');
INSERT INTO voicemail(context, mailbox, password, email) VALUES ('default', '930000004', '1234','tibanezlujan@gmail.com');

Llamo, me salta la locución… Pero vaya… No me llega nada… Claro, lo que me falta es configurar el servidor para que pueda enviar correos. Así que procedemos a instalar y configurar el exim4 para que envie mails:

root@vm-server-001:/etc/asterisk# apt-get install exim4

root@vm-server-001:/etc/asterisk#dpkg-reconfigure exim4-config

Seguimos pasos de https://wiki.debian.org/Exim y hecho, ya funciona nuestro servicio:

root@vm-server-001:/etc/asterisk#sendmail tibanezlujan@gmail.com < /tmp/email.txt

Volvemos a intentar dejar un mensaje, y efectivamente! El voicemail para los clientes que tenemos en Kamailio ya funciona!!! Por cierto, para configurar el correo que recibimos (el texto, subject,etc…) hemos de editar /etc/asterisk/voicemail.conf.

Bueno, una vez esto listo, debemos de proceder a parte 2: Cómo hacer que nuestros usuarios puedan activar y desactivar el buzón de voz.

¡Espero que os haya sido de utilidad!

Referencias:

http://kb.asipto.com/asterisk:realtime:kamailio-4.0.x-asterisk-11.3.0-astdb

http://www.voip-info.org/wiki/index.php?page_id=1738&comments_page=1

http://www.kamailio.org/dokuwiki/doku.php/asterisk:voicemail-system

https://wiki.debian.org/Exim

Kamailio – Enrutando llamadas hacia nuestro provider o SBC

Nuestro primer objectivo es levantar un troncal entre un Asterisk y nuestro Kamailio autenticado por IP. Para ello, lo primero que vamos a hacer es añadir salida PSTN en nuestro archivo de kamailio.cfg.

Para ello, simplemente tenemos que pasearnos por su archivo de configuración y leer. La adición de troncales para llamadas a través de PSTN (SIP Trunks) permite uno sólo uno por defecto (en post posteriores veremos cómo hacer LCRs y añadir otras salidas).

 # *** To enable PSTN gateway routing execute:
 # - define WITH_PSTN
 # - set the value of pstn.gw_ip
 # - check route[PSTN] for regexp routing condition

Aquí lo ponemos la dirección IP hacia la que queremos enviar la llamada saliente, en nuestro caso 92.127.91.91:

>> #!ifdef WITH_PSTN
>> # PSTN GW Routing
>> #
>> # - pstn.gw_ip: valid IP or hostname as string value, example:
>> # pstn.gw_ip = "10.0.0.101" desc "My PSTN GW Address"
>> #
>> # - by default is empty to avoid misrouting
>> pstn.gw_ip = "92.127.91.91"
>> pstn.gw_port = "5060"
>> #!endif

Luego editamos la parte de PSTN dentro de la lógica de llamadas, y aceptamos qué queremos que acepte y envíe. para nuestro caso, lo que hemos hecho es dehar que se llame a todo lo que comience por +XX o por 00 en el primer if, así como por 6,7,8 y 9. En caso de que no comience por estos números, lo que hacemos es descartar esta llamada con un “408 – Toni Not Allowed – Bad Format Number.”

Por otro lado, los números 906 y especiales (de pago añadido) tambióen los descartamos en el siguiente if, respondiendo con un “409 – Toni Not Allowed – Special Number.”

route[PSTN] {
#!ifdef WITH_PSTN
 # check if PSTN GW IP is defined
 if (strempty($sel(cfg_get.pstn.gw_ip))) {
 xlog("SCRIPT: PSTN rotuing enabled but pstn.gw_ip not defined\n");
 return;
 }
 # route to PSTN dialed numbers starting with '+' or '00'
 # (international format)
 # - update the condition to match your dialing rules for PSTN routing
 if(!($rU=~"^(\+|00)[1-9][0-9]{6,20}$") && !($rU=~"^(6|7|8|9)[0-9][0-9]{5,20}$")){
 sl_send_reply("408", "Toni Not Allowed - Bad Format Number.");
 xlog("**************************SCRIPT: ERROR IN FORMAT NUMBER\n");
 return;
 }
if(($rU=~"^(8|9)[0][3-7]{6,20}$")){
 sl_send_reply("409", "Toni Not Allowed - Special Number.");
 xlog("**************************SCRIPT: SPECIAL NUMBER NOT ALLOWED\n");
 return;
 }
# only local users allowed to call
 if(from_uri!=myself) {
 sl_send_reply("403", "Not Allowed");
 exit;
 }
if (strempty($sel(cfg_get.pstn.gw_port))) {
 $ru = "sip:" + $rU + "@" + $sel(cfg_get.pstn.gw_ip);
 } else {
 $ru = "sip:" + $rU + "@" + $sel(cfg_get.pstn.gw_ip) + ":"
 + $sel(cfg_get.pstn.gw_port);
 }
route(RELAY);
 exit;
#!endif
return;
}

Espero que os haya sido de utilidad, y recordad que los endpoints (en este caso vuestro Asterisk y vuestro Teléfono VoIP, por si os llegasen mensajes de tipo “488 – Not acceptable here.”.

IMPORTANTE:

Si vamos a utilizar DIDs para llamar entre nuestros usuarios, es necesario que cambiemos el orden en request_route para route(PSTN) y route(LOCATION), dado que si no, lo primero que hacemos es enviar la llamada hacia el exterior, sin mirar antes si la tenemos en nuestro dominio.

# user location service: Primero miramos si está en location table, y de ser así, procedemos a llamar. En caso contrario, lanzamos llamada contra PSTN.

 route(LOCATION);

# dispatch destinations to PSTN, ya que no está en LOCATION nuestro número.
 route(PSTN);

# # user location service, comentado por motivos explicados anteriormente.
# route(LOCATION);

Monitorizando un Asterisk en Observium

Observium es una plataforma de monitorización para diferentes plataformas de hardware y sistemas operativos, y que nos permite ver el estado de servicios y servidores tal y como hace Cacti.

Observium Comunidad es libre y de código abierto disponible. En este post no vamos a entrar en la instalación de esta plataforma, si no en la adición de servidores Asterisk, para poder conseguir ver el estado de los peers registrados, los canales concurrentes y otros.

Paso 1: Miramos si tenemos instalado xinetd en servidor Asterisk

Si se trata de Debian:

root@asteriskdebian001:/home# dpkg --get-selections | grep xinetd
xinetd install
root@asteriskdebian001:/home#

Si se trata de CentOS:

[root@asteriskcentos001 toni]# rpm -qa | grep xinetd
xinetd-2.3.14-39.el6_4.x86_64
[root@asteriskcentos001 toni]#

En caso de que no se encuentre instalado hacer un “apt-get install” o “yum install” según si se trata de debian o centos.

Paso 2: Creamos en el Asterisk que queremos monitorizar demonio

Es importante mencionar que vamos a utilizar un puerto no conocido (tcp/36602) y filtraremos nuestra dirección IP a través de archivo /etc/xinetd.d/observium_agent:

service app-asterisk
{
 type = UNLISTED
 port = 36602
 socket_type = stream
 protocol = tcp
 wait = no
 user = root
 server = /usr/bin/observium_agent/asterisk

 #configure the IPv[4|6] address(es) of your Observium server here:
 only_from = 91.127.206.232

 # Don't be too verbose. Don't log every check. This might be
 # commented out for debugging. If this option is commented out
 # the default options will be used for this service.

 log_on_success =
 disable = no
}

Paso 3: Creamos script que se va a encargar de conectarse a Asterisk y sacar datos

root@asteriskdebian001:/home#mkdir /usr/bin/observium_agent
root@asteriskdebian001:/home#vi /usr/bin/observium_agent/asterisk

Contenido de fichero/script:

#!/bin/bash

####### Asterisk Telephony Server
if [ -a /usr/sbin/asterisk ]
then
 echo '<<<app-asterisk>>>'
 ACTIVECHAN=$(asterisk -rx 'core show channels' | grep 'active channels' | cut -d' ' -f1)
 ACTIVECALL=$(asterisk -rx 'core show channels' | grep 'active call' | cut -d' ' -f1)
 IAXCHANNELS=$(asterisk -rx 'iax2 show channels' | grep active | cut -d' ' -f1)
 SIPCHANNELS=$(asterisk -rx 'sip show channels' | grep active | cut -d' ' -f1)
 SIPTOTALPEERS=$(asterisk -rx 'sip show peers' | grep 'sip peers' | cut -d' ' -f1)
 SIPONLINE=$(asterisk -rx 'sip show peers' | grep -o '[0-9]* online' | head -1 | cut -d' ' -f1)
 IAXTOTALPEERS=$(asterisk -rx 'iax2 show peers' | grep 'iax2 peers' | cut -d' ' -f1)
 IAXONLINE=$(asterisk -rx 'iax2 show peers' | grep -o '[0-9]* online' | head -1 | cut -d' ' -f1)

 echo "activechan:$ACTIVECHAN"
 echo "activecall:$ACTIVECALL"
 echo "iaxchannels:$IAXCHANNELS"
 echo "sipchannels:$SIPCHANNELS"
 echo "sippeers:$SIPTOTALPEERS"
 echo "sippeersonline:$SIPONLINE"
 echo "iaxpeers:$IAXTOTALPEERS"
 echo "iaxpeersonline:$IAXONLINE"

fi

No nos olvidemos de dar permisos de ejecución a este script:

root@asteriskdebian001:/home#chmod +x /usr/bin/observium_agent/asterisk

Finalmente reiniciamos xinetd:

root@asteriskdebian001:/home#service xinetd restart

Podemos probar el script de la siguiente forma:

root@asteriskdebian001:/home# /usr/bin/observium_agent/asterisk
<<<app-asterisk>>>
activechan:0
activecall:0
iaxchannels:0
sipchannels:236
sippeers:123
sippeersonline:98
iaxpeers:3
iaxpeersonline:2
root@asteriskdebian001:/home#

Paso 4: Añadimos host en nuestro observium

Para que pinte, en nuestro observium deberemos de poner en “Modules”>>”Poller Modules” el “unix-agent” en enabled. Una vez realizado esto, en un tiempo, en la pestaña de “Applications”.

PeersObservium

Referencias:

http://klaverstyn.com.au/david/wiki/index.php?title=Observium_Monitoring_Asterisk

Configurando SRTP + TLS

Hasta ahora lo que hemos realizado es una encriptación del tráfico de SIP a través del protocolo TLS (SIP/TLS) tal y como hemos visto en las páginas anteriores. Sinembargo, ¿qué sucede con el tráfico RTP? ¿Qué sucede con lo que no es señalización y es el audio?

Pues lo que pasa es que con SIP/TLS esto no se encripta, y sigue funcionando en texto plano. Es decir, cualquier persona que se encuentre en medio de una comunicación puede escucharla sin problema utilizando un analizador de redes y luego decodificandola (que no desencriptandola).

TLS nos permite establecer un canal seguro entre dos extremos, el principal objetivo de TLS es ofrecer privacidad e integridad, lo cual hemos utilizado para SIP. En el caso del audio utilizaremos SRTP.

SRTP (Secure RTP) es un protocolo de voz que añade confidencialidad, autenticación de mensajes, y protección ante la reproducción (no repudio). Es ideal para nuestras comunicaciones de voz ya que utiliza una compresión de tráfico en las cabeceras de los paquetes. Crea una clave de stream para cada paquete RTP, lo cual hace casi imposible que alguien pueda decodificar el paquete RTP del stream. El hecho de que no permita la reproducción (no repudio) quiere decir que si alguien dice “el árbol es verde” esto no puede ser modificado por “el árbol es rojo” u otros mensajes.

Resumiendo, SRTP nos proporciona:

* Confidencialidad

* Integridad

* No repudio

¡Procedamos a configurar nuestro Asterisk pues!

Paso 1: Cargamos módulo SRTP (en mi caso ya lo tenía activado)

netvoipAst*CLI> module show like srtp
Module Description Use Count 
res_srtp.so Secure RTP (SRTP) 0 
1 modules loaded
netvoipAst*CLI>

Paso 2: Editamos el sip.conf para que soporte TLS y nuestro peer también

[general]

;TLS Support
tcpenable=no
tlsenable=yes
tlsbindaddr=0.0.0.0
tlscertfile=/etc/asterisk/cert/asterisk.voiptest.netvoip.no-ip.org.pem
tlsdontverifyserver=no
tlscipher=DES-CBC3-SHA
tlsclientmethod=tlsv1

;SRTP Support
encryption=yes

[srtptls](!)
nat=yes
canreinvite=no
direcrtp=no
directmedia=no
disallow=all
allow=ulaw
allow=alaw
encryption=yes

[tls](!)
tranport=tls
type=peer
host=dynamic
qualify=yes

[nevoip]
context=netvoip-dialplan
secret=noexistneither
accountcode=netvoip
parkinglot=parkinglot_netvoip
call-limit=2
nat=yes
qualify=5000
callgroup=1
pickupgroup=1
domain=netvoip.pbx.netvoip.no-ip.org,netvoip-dialplan

Paso 3: Configuramos nuestros clientes y verificamos que está todo ok en Asterisk:

[1000](netvoip,tls,srtptls)
secret=testingpasswordinvented1
callerid="Zoiper - Toni - TLS" <1000>
mailbox=1006@netvoip


[1001](netvoip,tls,srtptls)
secret=testingpasswordinvented2
callerid="Cisco - Toni - TLS" <1001>
mailbox=1008@netvoip

Paso 4: Hacemos captura para ver si funciona y capturamos con Wireshar

Hacemos una llamada y capturamos el tráfico. En mi caso, para realizar la llamada he utilizado un softphone de tipo Zoiper, el cual tenía configurado contra otros servidores sin encriptación:

CapturaSRTP_TLS

Tal y como se puede ver, todo funcionó perfectamente! =)

¡TIP PARA ZOIPER!

He intentado configurar un cliente Zoiper y en principio no me dejaba ni registrarme contra mi Asterisk. Cual ha sido mi sorpresa cuando me he dado cuenta de que es necesario activar una opción extra para que aceptase el certificado desde mi Asterisk (¡el cual no tengo firmado con ninguna CA!).

zoiperCA

Esto es genial, dado que así podremos evitar ataques de MITM. En cualquier caso, como esto de momento cuesta dinerillo, lo pongo en modo inseguro, tal y como se ve en la imagen, y… ¡Adelante!

¡TIP PARA CISCO!

En los terminales Ciscos hemos de configurar lo siguiente para que nos funcione el SRTP:

SIP >> SRTP Method = s-descriptor
Phone >> Secure Call Serv = Yes
User >> Secure Call Setting = Yes

ciscoSRTP

Para el caso de mis terminales Grandstream y Snom, por razones logísticas aún no he tenido tiempo de configurarlos. En cuanto pueda, los subiré en este mismo apartado.

¡Espero que os haya sido de utilidad!

Fuentes:

http://www.voip-info.org/wiki/view/Asterisk+SRTP

http://blog.voz-ip.com/2011/tlssrtp-en-asterisk-1-8/

https://www.sinologic.net/blog/2012-03/solucion-al-problema-del-srtp-en-equipos-grandstreamr-con-asteriskr-y-de-paso-un-par-de-tips-de-regalo.html#.VHyQIfmG-uQ