Posts in Category: MySQL

Autenticación en OpenSIPS con MySQL

En esta parte usaremos una base de datos para registrar mediante una contraseña nuestros usuarios SIP dando un tanto mas de seguridad a nuestro pequeño sistema, y de tener en tablas todas las preferencias de nuestros usuarios, dominios, direcciones y grupos como veremos consecuentemente.

Partimos del hecho de que contamos con nuestra base de datos MySQl correctamente instalada y con nuestra contraseña de root configurada. Debemos realizar ciertas modificaciones al archivo opensipsctlrc (/usr/local/etc/opensips/opensipsctlrc), el cual debe quedar de la siguiente forma:

trantor:/usr/local/etc/opensips# cat opensipsctlrc | grep -v "#" | sed -e '/^$/d'
 SIP_DOMAIN=192.168.1.161
 DBENGINE=MYSQL
 DBHOST=localhost
 DBNAME=opensips
 DBRWUSER=opensips
 DBRWPW="opensipsrw"
 DBROUSER=opensipsro
 DBROPW=opensipsro
 ALIASES_TYPE="DB"
 OSIPS_FIFO="/tmp/opensips_fifo"
trantor:/home/gabriel#

Creamos la base de datos.

trantor:/home/gabriel/SIP# opensipsdbctl create
MySQL password for root:
INFO: test server charset
INFO: creating database opensips ...
INFO: Core OpenSIPS tables succesfully created.
Install presence related tables? (y/n): y
INFO: creating presence tables into opensips ...
INFO: Presence tables succesfully created.
Install tables for imc cpl siptrace domainpolicy carrierroute userblacklist? (y/n): y
INFO: creating extra tables into opensips ...
INFO: Extra tables succesfully created.
trantor:/home/gabriel/SIP#

Cambiamos la configuración de opensips.cfg por la configuración que se muestra a continuación la cual simbólicamente denominaremos opensips.cfg.1.

####### Global Parameters #########
debug=3
log_stderror=no
log_facility=LOG_LOCAL0
 
fork=yes
children=4
 
port=5060
 
/* (default bind on all available) */
#listen=udp:192.168.1.161:5060
 
####### Modules Section ########
 
#set module path
mpath="/usr/local/lib/opensips/modules/"
 
/* uncomment next line for MySQL DB support */
loadmodule "db_mysql.so"
loadmodule "auth.so"
loadmodule "auth_db.so"
loadmodule "signaling.so"
loadmodule "sl.so"
loadmodule "tm.so"
loadmodule "rr.so"
loadmodule "maxfwd.so"
loadmodule "usrloc.so"
loadmodule "registrar.so"
loadmodule "textops.so"
loadmodule "mi_fifo.so"
loadmodule "uri.so"
loadmodule "xlog.so"
loadmodule "acc.so"
 
# ----- mi_fifo params -----
modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")
modparam("rr", "enable_full_lr", 1)
modparam("rr", "append_fromtag", 0)
 
# ----- usrloc params -----
modparam("usrloc", "db_mode",   0)
 
modparam("usrloc", "db_mode",   2)
modparam("usrloc", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")
 
 
# ----- uri params -----
modparam("uri", "use_uri_table", 0)
# ----- acc params -----
/* what sepcial events should be accounted ? */
modparam("acc", "early_media", 1)
modparam("acc", "report_ack", 1)
modparam("acc", "report_cancels", 1)
modparam("acc", "detect_direction", 0)
modparam("acc", "failed_transaction_flag", 3)
modparam("acc", "log_flag", 1)
modparam("acc", "log_missed_flag", 2)
modparam("acc", "db_flag", 1)
modparam("acc", "db_missed_flag", 2)
 
modparam("auth_db", "calculate_ha1", yes)
modparam("auth_db", "password_column", "password")
modparam("auth_db", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")
modparam("auth_db", "load_credentials", "")
 
 
route{
 
	if (!mf_process_maxfwd_header("10")) {
		sl_send_reply("483","Too Many Hops");
		exit;
	}
 
	if (has_totag()) {
		if (loose_route()) {
			if (is_method("BYE")) {
				setflag(1); # do accounting ...
				setflag(3); # ... even if the transaction fails
			} else if (is_method("INVITE")) {
				record_route();
			}
			route(1);
		} else {
			if ( is_method("ACK") ) {
				if ( t_check_trans() ) {
					t_relay();
					exit;
				} else {
					exit;
				}
			}
			sl_send_reply("404","Not here");
		}
		exit;
	}
 
	if (is_method("CANCEL"))
	{
		if (t_check_trans())
			t_relay();
		exit;
	}
 
	t_check_trans();
 
        if (!(method=="REGISTER") && from_uri==myself)
        {
              if (!proxy_authorize("", "subscriber")) {
                      proxy_challenge("", "0");
                      exit;
              }
              if (!db_check_from()) {
                      sl_send_reply("403","Forbidden auth ID");
                      exit;
              }
 
              consume_credentials();
              # caller authenticated
        }
 
 
	if (loose_route()) {
		xlog("L_ERR",
		"Attempt to route with preloaded Route's [$fu/$tu/$ru/$ci]");
		if (!is_method("ACK"))
			sl_send_reply("403","Preload Route denied");
		exit;
	}
 
	# record routing
	if (!is_method("REGISTER|MESSAGE"))
		record_route();
 
	# account only INVITEs
	if (is_method("INVITE")) {
		setflag(1); # do accounting
	}
	if (!uri==myself)
	{
		append_hf("P-hint: outboundrn");
		route(1);
	}
 
	if (is_method("PUBLISH"))
	{
		sl_send_reply("503", "Service Unavailable");
		exit;
	}
 
	if (is_method("REGISTER"))
	{
                if (!www_authorize("", "subscriber"))
                {
                      www_challenge("", "0");
                      exit;
                }
 
                if (!db_check_to())
                {
                      sl_send_reply("403","Forbidden auth ID");
                      exit;
                }
 
		if (!save("location"))
			sl_reply_error();
 
		exit;
	}
 
	if ($rU==NULL) {
		# request with no Username in RURI
		sl_send_reply("484","Address Incomplete");
		exit;
	}
 
	# do lookup with method filtering
	if (!lookup("location","m")) {
		switch ($retcode) {
			case -1:
			case -3:
				t_newtran();
				t_reply("404", "Not Found");
				exit;
			case -2:
				sl_send_reply("405", "Method Not Allowed");
				exit;
		}
	}
	# when routing via usrloc, log the missed calls also
	setflag(2);
	route(1);
}
 
route[1] {
	# for INVITEs enable some additional helper routes
	if (is_method("INVITE")) {
		t_on_branch("2");
		t_on_reply("2");
		t_on_failure("1");
	}
 
	if (!t_relay()) {
		sl_reply_error();
	};
	exit;
}
 
branch_route[2] {
	xlog("new branch at $run");
}
 
 
onreply_route[2] {
	xlog("incoming replyn");
}
 
 
failure_route[1] {
	if (t_was_cancelled()) {
		exit;
	}
}

Iniciamos OpenSIPS.

trantor:~# opensipsctl start
 
INFO: Starting OpenSIPS :
INFO: started (pid: 28716)

Agregamos el par de usuarios 1000 y 1001, a la base de datos y registramos nuestros agentes SIP.

gabriel@trantor:~$ sudo opensipsctl add 1000 1000
new user '1000' added
gabriel@trantor:~$ sudo opensipsctl add 1001 1001
new user '1001' added

Mostramos la traza SIP del registro de un usuario almacenando previamente en nuestra base de datos.

U 192.168.1.162:5061 -> 192.168.1.161:5060
REGISTER sip:192.168.1.161 SIP/2.0.
Via: SIP/2.0/UDP 192.168.1.162:5061;branch=z9hG4bK-6bdbbdbc.
From: Bozada <sip:1000@192.168.1.161>;tag=ea98cc30d70f560fo1.
To: Bozada <sip:1000@192.168.1.161>.
Call-ID: 5da1e386-fde63540@192.168.1.162.
CSeq: 32475 REGISTER.
Max-Forwards: 70.
Contact: Bozada <sip:1000@192.168.1.162:5061>;expires=3600.
User-Agent: Linksys/SPA2102-3.3.6.
Content-Length: 0.
Allow: ACK, BYE, CANCEL, INFO, INVITE, NOTIFY, OPTIONS, REFER.
Supported: x-sipura.
.
U 192.168.1.161:5060 -> 192.168.1.162:5061
SIP/2.0 401 Unauthorized.
Via: SIP/2.0/UDP 192.168.1.162:5061;branch=z9hG4bK-6bdbbdbc.
From: Bozada <sip:1000@192.168.1.161>;tag=ea98cc30d70f560fo1.
To: Bozada <sip:1000@192.168.1.161>;tag=c97b4d1cb1f3d0da549e06a8d482ef63.be3a.
Call-ID: 5da1e386-fde63540@192.168.1.162.
CSeq: 32475 REGISTER.
WWW-Authenticate: Digest realm="192.168.1.161", nonce="4b85d15b000000039d8eac02cb35f405c16770fd04ba2424".
Server: OpenSIPS (1.6.1-notls (i386/linux)).
Content-Length: 0.
.
U 192.168.1.162:5061 -> 192.168.1.161:5060
REGISTER sip:192.168.1.161 SIP/2.0.
Via: SIP/2.0/UDP 192.168.1.162:5061;branch=z9hG4bK-896f8b1c.
From: Bozada <sip:1000@192.168.1.161>;tag=ea98cc30d70f560fo1.
To: Bozada <sip:1000@192.168.1.161>.
Call-ID: 5da1e386-fde63540@192.168.1.162.
CSeq: 32476 REGISTER.
Max-Forwards: 70.
Authorization: Digest username="1000",realm="192.168.1.161",nonce="4b85d15b000000039d8eac02cb35f405c16770fd04ba2424",uri="sip:192.168.1.161",algorithm=MD5,response="5a8c46a3bd960218616aaed03240e631".
Contact: Bozada <sip:1000@192.168.1.162:5061>;expires=3600.
User-Agent: Linksys/SPA2102-3.3.6.
Content-Length: 0.
Allow: ACK, BYE, CANCEL, INFO, INVITE, NOTIFY, OPTIONS, REFER.
Supported: x-sipura.
.
U 192.168.1.161:5060 -> 192.168.1.162:5061
SIP/2.0 200 OK.
Via: SIP/2.0/UDP 192.168.1.162:5061;branch=z9hG4bK-896f8b1c.
From: Bozada <sip:1000@192.168.1.161>;tag=ea98cc30d70f560fo1.
To: Bozada <sip:1000@192.168.1.161>;tag=c97b4d1cb1f3d0da549e06a8d482ef63.274d.
Call-ID: 5da1e386-fde63540@192.168.1.162.
CSeq: 32476 REGISTER.
Contact: <sip:1000@192.168.1.162:5061>;expires=3600.
Server: OpenSIPS (1.6.1-notls (i386/linux)).
Content-Length: 0.
.

Y como un diagrama a veces vale mas, aquí mostramos la gráfica de la traza SIP anterior.

| 192.168.1.162     			| 192.168.1.161
|         Request: REGISTER             |
|(5061)   ------------------>  (5060)   |
|         Status: 401 Unauthorized      |
|(5061)   <------------------  (5060)   |
|         Request: REGISTER             |
|(5061)   ------------------>  (5060)   |
|         Status: 200 OK                |
|(5061)   <------------------  (5060)   |

Realizamos nuevamente una sencilla llamada del usuario 1001 al 1000, y esta es la traza SIP de la llamada, la principal diferencia respecto al esquema anterior, es la parte de la autentificación.
En este caso al realizar el INVITE de la llamada, el servidor responde con mensaje SIP 407 (autenticación requerida), nuestro agente SIP responde y si son correctos los parámetros dejara realizar el INVITE iniciando la llamada, el resto de la traza SIP es igual a la del post anterior.

| 192.168.1.163     				| 192.168.1.161 (proxy)			| 192.168.1.162
|         INVITE SDP ( h261)            	|                   			|
|(5060)   ------------------>  (5060)   	|                   			|
|         407 Proxy Authentication Required	|                   			|
|(5060)   <------------------  (5060)   	|                   			|
|         ACK       				|                   			|
|(5060)   ------------------>  (5060)   	|                   			|
|         INVITE SDP ( h261)            	|                   			|
|(5060)   ------------------>  (5060)   	|                   			|
|         100 Giving a try              	|                   			|
|(5060)   <------------------  (5060)   	|                   			|
|                   				|         INVITE SDP ( h261)            |
|                   				|(5060)   ------------------>  (5061)   |
|                   				|         100 Trying			|
|                   				|(5060)   <------------------  (5061)   |
|                   				|         180 Ringing                   |
|                   				|(5060)   <------------------  (5061)   |
|         180 Ringing                   	|                   			|
|(5060)   <------------------  (5060)   	|                   			|
|                   				|         200 OK SDP ( h261)            |
|                   				|(5060)   <------------------  (5061)   |
|         200 OK SDP ( h261)            	|                   			|
|(5060)   <------------------  (5060)   	|                   			|
|         ACK       				|                   			|
|(5060)   ------------------>  (5060)   	|                   			|
|                   				|         ACK       			|
|                   				|(5060)   ------------------>  (5061)   |
|         BYE       				|                   			|
|(5060)   ------------------>  (5060)		|                   			|
|                   				|         BYE       			|
|                   				|(5060)   ------------------>  (5061)   |
|                   				|         200 OK    			|
|                   				|(5060)   <------------------  (5061)   |
|         200 OK    				|                   			|
|(5060)   <------------------  (5060)   	|                   			|

Mediante el siguiente comando podemos observar a los usuarios registrados en el servidor.

trantor:~# opensipsctl ul show
Domain:: location table=512 records=2
        AOR:: 1000
                Contact:: sip:1000@192.168.1.162:5061 Q=
                        Expires:: 2336
                        Callid:: 5da1e386-fde63540@192.168.1.162
                        Cseq:: 32476
                        User-agent:: Linksys/SPA2102-3.3.6
                        State:: CS_SYNC
                        Flags:: 0
                        Cflag:: 0
                        Socket:: udp:192.168.1.161:5060
                        Methods:: 5183
        AOR:: 1001
                Contact:: sip:1001@192.168.1.163:5060;transport=udp Q=
                        Expires:: 3596
                        Callid:: d35fe6bb7fc5df8b6c76521a80310ba6@0.0.0.0
                        Cseq:: 2
                        User-agent:: SIP Communicator 1.0 CVS-Wed_Feb_24_19-45-25_CST_2010
                        State:: CS_NEW
                        Flags:: 0
                        Cflag:: 0
                        Socket:: udp:192.168.1.161:5060
                        Methods:: 4294967295

GlassFish y MySQL en OpenSolaris

Siguiendo con el orden de las cosas acerca de ir conociendo un poquito de OpenSolaris, y aprovechando el frió que asolo este fin de semana a la gran Tenochtitlan, decidí agregarle unos cuantos paquetes mas al sistema, entre ellos el servidor de aplicaciones glassfish para crear unas sencillas consultas MySQL mediante jsp, he aquí el procedimiento:

Instalamos el paquete de GlassFish, mediante el gestor de paquetes de OpenSolaris.

zeratul@aiur:~$ pfexec pkg install glassfish-2
zeratul@aiur:~$ pfexec pkg info glassfish-2
                         Nombre: web/glassfish-2
                       Resumen: GlassFish Java EE 5 Application Server
                      Categoría: Web Services/Application and Web Servers
                          Estado: Instalado
     Editor: opensolaris.org
                         Versión: 2.1
                         Versión: 5.11
                  Ramificación: 0.111
Fecha de empaquetado: Mon May 18 20:20:27 2009
                         Tamaño: 81.32 MB
                              FMRI: pkg:/web/glassfish-2@2.1,5.11-0.111:20090518T202027Z

Modificamos la linea que se muestra a continuación, presente en el siguiente archivo: /usr/appserver/config/asenv.conf, donde cambiaremos la ruta desde donde iniciaremos nuestro dominio, esto con el fin de establecer los archivos de configuración con los permisos asociados a nuestro usuario, se muestra la linea original comentada y la linea haciendo referencia a nuestro home.

#AS_DEF_DOMAINS_PATH=”/var/appserver/domains”
AS_DEF_DOMAINS_PATH=”/export/home/zeratul/appserver/domains”

Creamos el dominio con la siguiente instrucción, establecemos una contraseña para el usuario admin y dejamos la contraseña por defecto para el usuario master.

zeratul@aiur:~$ asadmin create-domain --user admin --adminport 4848 --savemasterpassword=true domain1
Please enter the admin password>
Please enter the admin password again>
Please enter the master password [Enter to accept the default]:>
Please enter the master password again [Enter to accept the default]:>
Using port 4848 for Admin.
Using default port 8080 for HTTP Instance.
Using default port 7676 for JMS.
Using default port 3700 for IIOP.
Using default port 8181 for HTTP_SSL.
Using default port 3820 for IIOP_SSL.
Using default port 3920 for IIOP_MUTUALAUTH.
Using default port 8686 for JMX_ADMIN.
Domain being created with profile:developer, as specified by variable AS_ADMIN_PROFILE in configuration file.
------ Using Profile [developer] to create the domain ------
XML processing for profile: Base document [/usr/appserver/lib/install/templates/default-domain.xml.template]. Profile name [developer]. Processing property [domain.xml.style-sheets].
 
The file in given locale [es_MX] at: [/usr/appserver/lib/install/templates/locales/es_MX/index.html] could not be found. Using default (en_US) index.html instead.
Security Store uses: JKS
Domain domain1 created.

Iniciamos el servicio.

zeratul@aiur:~$ asadmin start-domain domain1
Starting Domain domain1, please wait.
Default Log location is /export/home/zeratul/appserver/domains/domain1/logs/server.log.
Redirecting output to /export/home/zeratul/appserver/domains/domain1/logs/server.log
Domain domain1 failed to startup. Please check the server log for more details.
CLI156 Could not start the domain domain1.

Si se nos presenta el error anterior de que no se puede iniciar el dominio, agregamos el nombre del equipo al archivo hosts en la linea que hace referencia a la dirección de loopback.

zeratul@aiur:~$ cat /etc/hosts
::1 aiur aiur.local localhost loghost
127.0.0.1 aiur.local localhost loghost aiur	;Agregar el nombre del equipo al final de la linea (aiur)

Volvemos a iniciar el dominio donde iniciara correctamente el servicio.

zeratul@aiur:~$ asadmin start-domain domain1
Starting Domain domain1, please wait.
Default Log location is /export/home/zeratul/appserver/domains/domain1/logs/server.log.
Redirecting output to /export/home/zeratul/appserver/domains/domain1/logs/server.log
Domain domain1 is ready to receive client requests. Additional services are being started in background.
Domain [domain1] is running [Sun GlassFish Enterprise Server v2.1 (9.1.1) (build b60e-fcs)] with its configuration and logs at: [/export/home/zeratul/appserver/domains].
Admin Console is available at [http://localhost:4848].
Use the same port [4848] for "asadmin" commands.
User web applications are available at these URLs:
[http://localhost:8080 https://localhost:8181 ].
Following web-contexts are available:
[/web1  /__wstx-services ].
Standard JMX Clients (like JConsole) can connect to JMXServiceURL:
[service:jmx:rmi:///jndi/rmi://aiur.local:8686/jmxrmi] for domain management purposes.
Domain listens on at least following ports for connections:
[8080 8181 4848 3700 3820 3920 8686 ].
Domain does not support application server clusters and other standalone instances.

Nos dirigimos a un navegador web y mediante el puerto 8080, GlassFish nos debe dar su pagina de bienvenida.

glassfish1-1

Ahora necesitamos el controlador de Java para poder conectarnos a bases de datos MySQL, descargamos la ultima versión del siguiente sitio: http://dev.mysql.com/downloads/connector/j/

Necesitamos colocar el archivo .jar que viene en el archivo comprimido dentro de la carpeta ext que se ubica en la siguiente ruta: /export/home/zeratul/appserver/domains/domain1/lib/ext

zeratul@aiur:~/appserver/domains/domain1/lib/ext$ ls
mysql-connector-java-5.1.10-bin.jar

Paramos e iniciamos el servidor glassfish para que tome los cambios.

zeratul@aiur:~$ asadmin stop-domain domain1
zeratul@aiur:~$ asadmin start-domain domain1

Ahora realizaremos un pequeño archivo jsp para realizar una sencilla consulta al servidor MySQL que guarda los registros de llamadas de nuestro Asterisk. De manera rápida crearemos un archivo llamado listar.jsp, dentro de la carpeta: /export/home/zeratul/appserver/domains/domain1/docroot

<%@ page  import="java.io.*,java.util.*,java.net.*,java.sql.*" %>
<!DOCTYPE HTML PUBLIC  "-//W3C//DTD HTML 4.01 Transitional//EN"  "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head><title>Ejemplo consulta  JSP</title></head>
<body><center>
<%
Connection  canal = null;
Statement instruccion=null;
ResultSet tabla= null;
String conexion =  "jdbc:mysql://mysql.demerzel.org:3306/asteriskcdr?user=asterisk&password=mysecret";
 
//Abrir el enlace
try{
Class.forName("com.mysql.jdbc.Driver").newInstance();
canal =  DriverManager.getConnection(conexion);
instruccion =  canal.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
}
catch(ClassNotFoundException e){ out.println(e);}
catch(SQLException e){ out.println(e);}
try{
tabla =  instruccion.executeQuery("select src, dst, calldate, sec_to_time(billsec), channel, dstchannel from cdr where billsec!=0 and disposition='ANSWERED' and calldate between '2009-12-01 00:00:00' and '2009-12-31 23:59:59' order by calldate, src, dst limit 25");
out.println("<table border=1>");
out.println("<tr><th>Origen</th><th>Destino</th><th>Fecha</th><th>Duraci&oacute;n</th><th>Canal Origen</th><th>Canal Destino</th></tr>");
while(tabla.next()){
out.println("<tr><td>"+tabla.getString(1)+"</td><td>"+tabla.getString(2)+"</td><td>"+tabla.getString(3)+"</td><td>"+tabla.getString(4)+"</td><td>"+tabla.getString(5)+"</td><td>"+tabla.getString(6)+"</td></tr>");
}
out.println("</table>");
}
catch(Exception e){  out.println(e);}
%>
</center></body>
<html>

El servidor MySQL no esta en el mismo equipo por lo tanto debemos darle los permisos adecuados al usuario para realizar consultas desde OpenSolaris. Una sentencia sencilla como la siguiente sera suficiente:

GRANT SELECT ON asteriskcdr.* TO asterisk@192.9.200.114 IDENTIFIED BY 'mysecret';

Ingresamos a la dirección web http://midirecciónip:8080/listar.jsp, y se nos debe desplegar el listado de llamadas de las que hicimos consulta.

glassfish2-1

Referencias:
El articulo original de como instalar GlassFish.
http://blogs.sun.com/observatory/en_US/entry/glassfish
De aquí tome el archivo jsp de ejemplo.
http://casidiablo.net/instalacion-de-un-entorno-web-tomcat-jsp-mysql/

MySQL y Asterisk CDR

Realizaremos una pequeña descripción de como conectar mediante MySQL diferentes servidores Asterisk para que guarden los registros de las llamadas realizadas. En el ejemplo que se mencionara a continuación se tienen siete equipos Asterisk funcionando cada uno de ellos con tarjetas analógicas y/o digitales. En el diagrama que se muestra a continuación, se puede observar que estos Asterisk están conectados mediante una topología de estrella por así decirlo, cada servidor esta conectado al Asterisk principal mediante un túnel UDP (VTUN), de esta manera puede haber comunicación entre todos ellos pasando por el servidor central mediante trunks SIP e IAX2.

mysqlasterisk

Cada servidor almacenara en una base de datos alojada en el servidor principal todos los registros de llamadas que se realizan, en este caso solo es de mi interés primordial las llamadas que se realizan a la PSTN por cada equipo, ya que las llamadas realizadas entre servidores (de extensión a extensión) son fácilmente registradas en el CDR del servidor principal, por lo cual tendremos una base de datos con ocho tablas.

Asumimos que ya contamos nuestro Asterisk funcionando en cada conmutador, y que en cada uno de ellos hemos instalado el modulo cdr_addon_mysql, presente en los addons de Asterisk, es preciso indicar que se utilizara el campo uniqueid, este de manera predeterminada no viene activo cuando trabajamos con MySQL al guardar el CDR, así que debemos agregar la siguiente linea en el archivo Makefile que se encuentra de la carpeta de asterisk-addons-1.4.7 y despues de esto compilar e instalar.

ASTCFLAGS+=-DMYSQL_LOGUNIQUEID

Mas información al respecto la podemos encontrar en el siguiente enlace: http://www.voip-info.org/wiki/view/Asterisk+cdr+mysql

Instalamos MySQL mediante aptitude y establecemos una contraseña para el usuario root de nuestro sistema de base de datos.

asteriskpbx:~# aptitude install mysql-server-5.0 libmysqlclient-dev