lunes, 28 de septiembre de 2015

Error TXT DB 2 al generar certificados con easy-rsa

Recientemente estaba generando una lista de certificados digitales para un lote de routers que se van a desplegar, con tan mala suerte que en la lista de seriales de los routers habían 3 duplicados (justo al final y con diferentes nombres). Para la generación de los certificados utilizo como "Common Name (CN)" el serial del aparato, cual es mi sorpresa cuando casi al terminar, generando los últimos 3 me encuentro con el siguiente error:

"failed to update database TXT_DB error number 2"

Primera vez que observo tal error, y para colmo de males, el certificado parecía haberse creado, revisando el directorio donde los almaceno aparecían los mismos, me aventure a pensar que fue un error del sistema al procesarlos y que, con solo borrarlos y recrearlos todo estaría bien. Para mi desgracia al hacer esto ultimo, aparecía el mismo error de nuevo, googleandolo observo que este error solo lo arroja cuando se intenta crear un certificado cuyo CN ya esta registrado y la única forma de solventar esto es o revocando el certificado o esperando que expire (en 12 años en este caso). 

Pues nada hago el procedimiento estándar para revocar un certificado:

./revoke-full CN

Y me arroja un error diciendo que el certificado no se encuentra... Para los que no lo saben (yo no lo sabia) no se puede revocar un certificado digital sin tener el .crt (los cuales yo borre previamente) - Habiéndolo borrado desde la consola de Linux con rm, realmente mis esperanzas de recuperarlos eran pocas, y necesitaba tener esos certificados con el CN = Serial del router, dado que utilizo un script para autoconfigurar todos los routers y ellos descargan sus certificados de forma automática basándose en el serial así que utilizar otro CN no era una opción valida.

Resumiendo la solución, cuando se genera un certificado, se genera también un respaldo del archivo .crt con extensión .pem, solo que el nombre del mismo no concuerda con el CN (el nombre son unos caracteres HEX) y para poder ubicarlo entonces hay que revisar un archivo llamado index.txt (ubicado también en la carpeta keys). Los pasos son:

  • Abrimos el archivo index.txt de izquierda a derecha, hay 4 campos, primero una V o R (Valid o Revoked), siguiendo una serie de números, luego caracteres hex y por ultimo una linea larga que describe todo el certificado
  • Linea a linea buscamos y ubicamos el certificado cuyo CN concuerda con el .crt que borramos (dentro de la linea larga con la descripción del certificado)
  • El tercer campo (los caracteres HEX) nos dice el nombre del archivo .pem que es respaldo del .crt
  • Copiamos el archivo .pem que recién ubicamos en el mismo directorio pero colocando como nombre el CN y la extensión .crt 
  • Ahora si podemos utilizar ./revoke-full CN y funcionara
  • Borramos el .crt (nuevamente)

Ejemplo:

V       29000020045Z           15      unknown /C=MX/ST=SO/L=Hermosillo/O=pagina.com/OU=Conektame/CN=1000010B/name=servidor/emailAddress=correo@correo.com

En negrita están los datos que nos interesa, primero los caracteres HEX que identifican el archivo .pem y luego el CN que identifica el certificado. 

Tendríamos entonces que copias el archivo 15.pem a 1000010B.crt

De todo esto, solo recordar que:
  • Para revocar un certificado es necesario el .crt del mismo
  • los archivos .pem con copias de los archivos .crt generados 
  • Es conveniente hacer respaldos de todos los certificados y tenerlos en sitios diferentes para evitar inconvenientes como este en el futuro 
  • Si les da el error antes mencionado, recuerden, es porque ya generaron un certificado con ese CN

miércoles, 3 de junio de 2015

Cisco Dual-Wan (NAT)

Recientemente me encontré en la necesidad de asesorar a un cliente con un requerimiento que incluía realizar un balanceo de carga entre dos conexiones a Internet. En especifico los requerimientos fueron los siguientes:


  1. Balanceo de carga entre dos conexiones a Internet, pero este balanceo de carga debe de ser asimétrico, es decir, debe pasar mas trafico por una conexión que en la otra, en un ratio 1:2. 
  2. Se debe aplicar NAT a ambas conexiones. 
  3. Se debe realizar un seguimiento de cada conexión para deshabilitarla en caso de una falla indirecta en la misma. 
  4. Se requiere realizar port-forwarding en ambas conexiones a servicios y equipos específicos en la LAN. 

El siguiente diagrama, explica mejor la situación:





Lógicamente, el router que se debe configurar en esta ocasión, es el "NAT-ROUTER", En este caso, asumiremos lo siguiente:

  1. Los puertos conectados a los ISP son, F0/0 para el ISP01 y F0/1 para el ISP02
  2. El puerto conectado a la LAN es F1/0
  3. Del lado de la LAN solo existe una subred, 192.168.0.0/24
  4. Las IPs que nos asignaron los ISP son, ISP01 172.10.10.10 y ISP02 173.16.0.10
  5. Las puertas de enlace son ISP01 172.10.10.1 y ISP02 173.16.0.1

Para poder llevar a buen puerto este proyecto, se debe realizar lo siguiente:

Configurar NAT (PAT en este caso)

El proceso es exactamente el mismo que se realiza habitualmente, esto es, definir que interfaces son inside y que interfaces son outside, definir una lista de acceso con los hosts a los cuales se les realizara el NAT cuando salgan a internet, etc. Pero, adicionalmente, dado que esto es un entorno con dos WAN, es necesario definir reglas de NAT que permitan diferenciar cual se aplicara, según el puerto de salida del paquete.

Según documentación de Cisco, por la forma en que opera IOS con NAT, la simple definición de un ACL que defina los hosts que pueden conectarse a internet, no basta, dado que el sistema realiza una verificación de reglas NAT, luego de consultar la tabla de enrutamiento (y por ende, ya teniendo definida la interfaz de salida del paquete), esto implica que, salvo que definamos una regla NAT que adicionalmente considere la interfaz de salida, podemos terminar con una situación donde un paquete es traducido a una dirección de origen que no concuerda con la dirección de la interfaz de salida.

Ejemplo:

  1. Entra un paquete dirigido a 172.16.0.1 con origen 192.168.0.10, el router consulta su FIB (Tabla de Enrutamiento) y decide enviarlo por F0/0 (ISP01), la IP de esta interfaz es 172.17.0.10
  2. Luego de lo anterior, se consultan las reglas definidas para NAT, el router comprende que el paquete procede de una interfaz definida como inside y va dirigido a una interfaz outside, adicionalmente concuerda con una lista de acceso definida en la regla, realiza una traducción donde cambia la dirección de origen a 172.18.0.20 (la IP asignada a la interfaz F0/1, que conecta con ISP02).
  3. Envía el paquete por la interfaz F0/0
Normalmente un router solo enruta paquetes basado en la IP de destino, pero, que sucedería si el router del ISP02 en el caso anterior utilice algún mecanismo de filtrado o de Policy Based Routing? el paquete recibido por este no concuerda con la subred definida para ese enlace y podría perfectamente descartarlo precisamente por esta razón. 

Para solventar esto, debemos definir no solo listas de acceso de los hosts que queremos puedan tener conexion a internet, sino algo que nos permita definir que regla utilizar, segun la interfaz de salida seleccionada por el router. Para esto utilizaremos algo denominado en Cisco como "route maps". 

Estos mapas de ruta, permiten crear secuencias donde se definen diversos parámetros a evaluar (listas de acceso, interfaces de salida, DSCP, etc.) y solo devuelven como "verdadero" si todos se cumplen. 

Definiendo los route-maps

Definiremos dos route maps, uno por cada interfaz de salida que evaluen si la IP de origen del paquete y la interfaz de salida del mismo:

(en modo conf)
!Definimos primeramente nuestra ACL
ip access-list standard NAT_PERMITIDOS
   permit 192.168.0.0 0.0.0.255
!
!Este route map, verifica que el paquete salga por el ISP01
route-map 1 permit 10
   match ip address NAT_PERMITIDOS
   match interface fastethernet0/0
!
!Este route map, verifica que el paquete salga por el ISP02
route-map 2 permit 10
   match ip address NAT_PERMITIDOS
   match interface fastethernet0/1
!

Definiendo las reglas NAT

(en modo conf)
ip nat inside source route-map 1 interface fastethernet0/0 overload
ip nat inside source route-map 2 interface fastethernet0/1 overload

Como aprecian, no difiere mucho de la definicion de reglas NAT utilizando unicamente ACL.

Configuración de balanceo de carga y chequeo de conexión


Para rutas estáticas, balanceo de carga asimétrico es una función que no esta explicitamente definida en IOS, para lograr esto, jugaremos con la recursividad de las rutas, dado que normalmente los routers Cisco distribuyen el trafico de forma equitativa entre el numero de rutas que posean la misma métrica y la misma distancia administrativa, resulta evidente que, si creamos 3 rutas estaticas con la misma métrica, misma AD pero apuntando a diferentes salidas (2 al ISP01 y 1 al ISP02), obtendremos un balanceo de carga asimétrico con ratio 1:2 (dado que se reparte el 33% del trafico entre cada salida, pero dos de estas son la misma interfaz).

Adicionalmente, tenemos que considerar los problemas de conexión indirectos de cada ruta, normalmente una ruta es eliminada de la FIB cuando se detecta una falla directa de la interfaz de salida de dicha ruta (esto solo en el caso de rutas estáticas, en rutas aprendidas por protocolos de enrutamiento, el comportamiento es algo mas inteligente). ¿Qué sucede entonces cuando por problemas internos del ISP01 (por ejemplo) no se puede acceder a digamos, www.google.com (dado que el router decidió enviar el trafico hacia dicha pagina por este ISP), pero, la conectividad entre el NAT-ROUTER y el router de dicho ISP funciona correctamente? La ruta no se va a deshabilitar, ocasionando que se siga utilizando, lógicamente el trafico jamas alcanzara la pagina web de google y ahí es cuando tendremos al típico usuario llamando para decir "no hay internet".

Tenemos que utilizar algun mecanismo que permita monitorear el funcionamiento de la conexión, mas allá de la disponibilidad del enlace entre ambos routers. Con Cisco, tenemos una herramienta denominada IP SLA, el único problema de este comando, es que solo esta disponible en routers que posean licencia DATA. En cualquier caso, el procedimiento es como sigue:

Creamos los IP SLA

Estas son reglas de chequeo de servicios, en este caso crearemos dos reglas que chequeen la conectividad con www.google.com por medio de ICMP, una regla utiliza como interfaz de salida la del ISP01 y la otra la del ISP02.

(en modo conf)
ip sla 1 
   icmp-echo www.google.com source-ip 172.10.10.10
   frequency 10
!
ip sla 2
   icmp-echo www.google.com source-ip 173.16.0.10
   frequency 10
!
ip sla schedule 1 life forever start-time now
ip sla schedule 2 life forever start-time now
!

Frequency define cada tanto tiempo en segundos se debe realizar la prueba (en este caso 10 segundos) icmp-echo indica el tipo de prueba a realizar (ping) a que destino y con que origen (notese que los orígenes coinciden con las IP asignadas a nosotros por los ISP). IP SLA SCHEDULE, define cuando comienza a funcionar la prueba, en este caso empieza de inmediato y se debe mantener en funcionamiento de forma permanente. Si quieren verificar el funcionamiento basta utilizar el comando show ip sla.

Creamos los objetos TRACK

Estos objetos permiten en conjunto con los IP SLA devolver un estado verdadero o falso, según análisis de los resultados devueltos por IP SLA. En este caso, queremos que se tome cada IP SLA definido y se analice si existe o no conectividad, utilizamos lo siguiente:

(en modo conf)
track 1 ip sla 1 reachability
track 2 ip sla 2 reachability

Nota: En versiones anteriores de IOS los comandos antes expuestos no funcionan, si este es el caso, se debe hacer uso de los siguientes:

(en modo conf)
track 1 rtr 1 reachability

track 2 rtr 2 reachability

Configuramos las rutas estáticas

Finalmente creamos las rutas estáticas correspondientes, sin embargo, estas rutas tienen un añadido como se observa a continuación:

(en modo conf)
ip route add 0.0.0.0 0.0.0.0 172.10.10.1 track 1
ip route add 0.0.0.0 0.0.0.0 173.16.0.1 track 2
ip route add 0.0.0.0 0.0.0.0 fastethernet0/0 track 1

En este caso, observen el añadido de la palabra clave track, seguido de un numero que concuerda con los objetos track que creamos previamente. Esto le indica al router que solo debe instalar la ruta en la FiB cuando el objeto track devuelve como resultado de la prueba "verdadero" esto es, cuando se tiene conectividad con www.google.com, en caso contrario la ruta se elimina, evitando enviar trafico por esta si no se tiene un correcto funcionamiento. Ademas, también deben apreciar que existe una ruta adicional que apunta a la interfaz f0/0 (ISP01) ademas de la ruta que apunta directamente a la IP gateway de este ISP, esto es lo que comentaba de la recursividad y el balanceo de carga, las 3 rutas funcionan correctamente, tienen la misma AD y la misma métrica, dos de estas salen por la misma interfaz, recordemos que los routers Cisco envían de forma equitativa el trafico entre cada ruta, por ende aquí estamos obteniendo un balanceo de carga asimétrico 1:2 (por cada paquete que sale por F0/1, dos salen por F0/0).

Configuración Port-Forwarding

En este caso solo dejare la plantilla para realizar esto, se debe llenar por cada puerto que se requiera abrir. 

ip nat inside source static tcp/udp host_destino p_destino 172.10.10.10 p_origen extendable
ip nat inside source static tcp/udp host_destino p_destino 173.16.0.1 p_origen extendable

jueves, 6 de noviembre de 2014

Vlan Trunking - Cisco Vs Mikrotik

En el mundo de las redes no siempre se tiene la posibilidad de trabajar con hardware de un mismo vendedor, ya sea por disponibilidad del mismo o que sencillamente por relación costo/beneficio nos conviene crear ambientes donde interactuen dispositivos de distintas marcas.

Cuando esto sucede, es el deber del Ingeniero encargado del despliegue de la red, garantizar que los dispositivos inter-operen entre si correctamente. Esto no suele ser algo sencillo, especialmente porque muchas marcas tienden a agregar "extras" a los protocolos y estándares actualmente definidos, normalmente estos extras son propietarios y es entonces cuando comienzan los problemas.

Situación 

Se desea crear un enlace layer 2 entre un router y un switch por donde puedan circular tramas 802.1Q, es decir, en terminología Cisco, un "Trunk Port". Por otro lado, se tienen 3 enlaces a otro switch desde el mismo router, pero que no utilizan el protocolo 802.1Q (puertos en modo access).

 Equipos que intervienen:

Router: Mikrotik CCR1036-12G-4S corriendo RouterOS v6.20
Switch: Cisco 2960S-48LPS-L

Topologia:


Como se puede apreciar, tenemos un enlace troncal (las dos lineas representan dos interfaces unidas por medio de LACP) entre el router y un switch, del otro lado (a la izquierda), apreciamos que tenemos 3 enlaces entre el router y el switch, estos enlaces no son troncales (no se realiza marcaje de VLANs), sino que están en modo acceso.

En teoría esto es tan sencillo como configurar el switch de la izquierda con los 3 puertos en sus VLANs respectivas, el switch de la derecha con el puerto (port channel) en modo trunk y permitir el paso de las VLANs 100, 110 y 120. Del lado de Mikrotik basta con crear un bridge por cada VLAN, agregarle una dirección IP y agregar a este bridge todos los puertos que intervienen. La Configuración a continuación:

Configuración Switch de la derecha:
 interface GigabitEthernet1/0/51  
  switchport mode trunk  
  channel-protocol lacp  
  channel-group 1 mode active  
 !  
 interface GigabitEthernet1/0/52  
  switchport mode trunk  
  channel-protocol lacp  
  channel-group 1 mode active  
 !  

Configuracion Router:
 /interface bridge  
 add l2mtu=1590 name=BR-VLAN-100 priority=0x6000  
 add l2mtu=1590 name=BR-VLAN-110 priority=0x6000  
 add l2mtu=1590 name=BR-VLAN-120 priority=0x6000  
 /interface bridge port  
 add bridge=BR-VLAN-120 interface=VLAN-120  
 add bridge=BR-VLAN-100 interface=VLAN-100  
 add bridge=BR-VLAN-120 interface=ether3  
 add bridge=BR-VLAN-100 interface=ether1  
 add bridge=BR-VLAN-110 interface=ether2  
 add bridge=BR-VLAN-110 interface=VLAN-110  
 /interface bonding  
 add mode=802.3ad name=Ofc-Con slaves=sfp1,sfp2  
 /interface vlan  
 add interface=Ofc-Con name=VLAN-100 vlan-id=100  
 add interface=Ofc-Con name=VLAN-110 vlan-id=110  
 add interface=Ofc-Con name=VLAN-120 vlan-id=120  
 /ip address  
 add address=10.10.10.129/26 comment="INTERFAZ DE ACCESO USUARIOS-PC" interface=BR-VLAN-110 network=10.10.10.128  
 add address=10.10.10.193/26 comment="INTERFAZ DE ACCESO USUARIOS-WIFI" interface=BR-VLAN-120 network=10.10.10.192  
 add address=10.10.10.1/25 comment="INTERFAZ DE ACCESO A SERVIDORES, IMPRESORAS, ADMINISTRACION Y TELEFONOS" interface=BR-VLAN-100 network=10.10.10.0  

La configuración del switch de la izquierda la omito porque es muy obvia (configurar cada interfaz con switchport mode access, switchport access vlan XXX).

En teoría, esto debería de funcionar correctamente, pero no es así. Si colocaramos una PC en la VLAN 100 por medio del switch de la derecha y luego otra PC en la misma VLAN pero en el switch de la izquierda e hiciéramos un ping entre ellas, notaríamos que no tenemos conectividad.

Si revisamos los logs de ambos switches, observaríamos que todos los puertos que conectan al router estan bloqueados por "SPANNING-TREE INCONSISTENCIES".

¿Cual es la razón de esto?

Cisco, añade una extensión propietaria al protocolo spanning-tree que permite tener una instancia del mismo por cada VLAN, esto lo denominaron Per VLAN Spanning-tree (PVSTP) incluso el protocolo Rapid Spanning Tree funciona con este añadido (PVSTP+). Esto no es algo que se pueda desactivar, es decir no se puede tener el "spanning tree solo".

Mikrotik trabaja con STP y STP+ pero las versiones estandarizadas en los RFC. En conexiones a switches Cisco en modo access no hay problema con esto dado que existe una sola instancia de STP, sin embargo cuando se conecta un router MK y un switch Cisco en modo trunk el STP no funciona correctamente.

En este caso cuando el router recibe una BPDU PVST, no sabe que hacer con ella y sencillamente hace un flooding de la misma a todos los puertos que conforman el bridge que configuramos (en lugar de procesarla), el switch del lado izquierdo recibe esta BPDU y al ser un aparato Cisco detecta que la BPDU es para un puerto en modo Trunk no en modo access (como es el caso actual). Por esta razon decide bloquear el puerto arrojando el error antes mencionado. Lo mismo pasa en el sentido opuesto, el switch del lado derecho recibe una BPDU "tradicional" y decide entonces bloquear el puerto con el mismo error.

Solución 

Lo mas evidente seria desactivar STP (algo que de verdad nunca es recomendable), si bien Cisco no permite desactivar la extension "per vlan", y tampoco se puede realmente deshabilitar STP por cada puerto (desactivar el STP implica desactivarlo globalmente). Se puede utilizar un comando que filtra las BDPU de un puerto, es decir, evita que sean enviadas por ese puerto y evita que las recibidas en este sean procesadas.

El comando se debe aplicar directamente a la interfaz y es:

spanning-tree bpdufilter enable

Con esto logramos que todo funcione correctamente. 








domingo, 5 de octubre de 2014

Cisco 7940G y Asterisk - Parte 3

Ahora hablaremos de como asignar un logo al teléfono y luego la aplicación de directorio.

Asignación del logo

Esto es relativamente sencillo, primero, necesitan un logo que cumpla con las siguientes características:

1.- Formato BMP
2.- En escala de grises, indexado.
3.- Tamaño máximo 90x56 px.

El teléfono accede a este archivo por medio de HTTP, así que deben tener también un servidor HTTP, guardar el logo en este y colocar el URL de acceso del mismo de la siguiente forma, ya sea en el archivo SIPDefault.cnf o en el archivo de cada teléfono SIP.cnf:

logo_url: "URL del logo"

Por ejemplo, si el logo se encuentra en 192.168.0.1/asterisk/logo.bmp, deben colocar:

logo_url: "http://192.168.0.1/asterisk/logo.bmp"

Si por ejemplo poseen servidores de nombre (DNS) y 192.168.0.1 tiene asignado el registro "httpserver.dominiolocal.com" colocan:

logo_url: "http://httpserver.dominiolocal.com/asterisk/logo.bmp"

Es decir, colocal el FQDN en lugar de la IP, cabe acotar que el telefono solo descarga el logo cuando arranca, por ende si realizan algún cambio al mismo, para que se vea reflejado deberán reiniciar el teléfono (que si no lo había dicho antes, se puede realizar presionando las teclas settings + asterisco + 6).

Aplicación de directorio

Algo que me agrado mucho, es que los teléfonos 7940G permiten correr microaplicaciones escritas en xml, en este archivo PDF tienen una concisa guía de como escribir estas aplicaciones, en mi caso la aplicación de directorio funciona así:

1.- La aplicación XML en el teléfono se encarga de la presentación al usuario de un menú para poder realizar las búsquedas y luego mostrar los resultados obtenidos. La aplicación es accesible presionando la tecla "directory" en el teléfono y seleccionando "external directory".
2.- Si el usuario desea buscar algún contacto interno (extensión), selecciona la opción "directorio interno local. Se ejecuta un script PHP.
3.- Cuando el usuario desea buscar algún contacto externo, selecciona la opcion "buscar contacto", introduce los datos de este, la aplicación XML se encarga de pasar estos datos como una variable a un script PHP.
4.- Ambos scripts interactuan con una base de datos en MYSQL, los cuales generan una salida en formato XML que el teléfono interpreta para luego mostrar al usuario.

Para que el teléfono haga uso de esta aplicación deben incluir ya sea en el archivo SIPDefault.cnf o en el archivo individual de cada teléfono SIP.cnf, la siguiente linea:

directory_url: "URL del archivo xml principal"

Mismas reglas que con el logo, el teléfono accede al archivo XML es mediante HTTP.

Abajo encontraran los códigos fuentes de los archivos XML y PHP, esta aplicación es muy sencilla y la escribí leyendo la guía en PDF que deje mas arriba y unas cuantas guías de W3Schools

menu1.xml es el archivo al que accede el teléfono y se referencia en la linea "directory_url", este genera un menú con dos opciones, según la opción que se presione se llama un archivo XML (buscar_contacto.xml) que le indica al teléfono que debe recibir un parámetro por parte del usuario (introducido utilizando el teclado) y luego enviarlo a un script php (busqueda.php) que a su vez genera una salida XML para que el teléfono la interprete, o se ejecuta un script PHP (interno.php) que genera a su vez una salida en formato XML, que el teléfono interpreta y luego muestra al usuario. El diagrama de flujo a continuación debería de dejar todo mas claro:



menu1.xml
 <CiscoIPPhoneMenu>  
  <Prompt>Directorio Telefonico</Prompt>  
  <MenuItem>  
   <Name>Buscar un contacto</Name>  
   <URL>URL buscar_contacto.xml</URL>  
  </MenuItem>  
  <MenuItem>  
   <Name>Directorio Interno Local</Name>  
   <URL>URL interno.php</URL>  
  </MenuItem>  
 </CiscoIPPhoneMenu>  

buscar_contacto.xml
 <CiscoIPPhoneInput>  
  <Title>Directorio telefonico</Title>  
  <Prompt>Criterio de busqueda</Prompt>  
  <URL>URL busqueda.php</URL>  
  <InputItem>  
   <DisplayName>Nombre</DisplayName>  
   <QueryStringParam>nombre</QueryStringParam>  
   <InputFlags>U</InputFlags>  
  </InputItem>  
 </CiscoIPPhoneInput>  


interno.php
 <?php  
 header('Content-Type: text/xml');  
 #DATOS DE CONEXION A LA BASE DE DATOS  
 $mysql_conn = mysqli_connect("IP O FQDN","USUARIO","CONTRASEÑA","BASE DATOS");  
 #VALORES A BUSCAR  
 $resultado = mysqli_query($mysql_conn,"SELECT * FROM contactos WHERE tag = 'ext'ORDER BY nombres");  
     print ("<CiscoIPPhoneDirectory>\n");  
     print ("<Title>");  
     print ("Directorio Telefonico");  
     print ("</Title>\n");  
     print ("<Prompt>");  
     print ("Coincidencias");  
     print ("</Prompt>\n");  
     while($row = mysqli_fetch_array($resultado))  
     {  
         print ("<DirectoryEntry>\n");  
             print ("<Name>");  
             print ($row['nombres']);  
             print ("</Name>\n");  
             print ("<Telephone>");  
             print ($row['numero']);  
             print ("</Telephone>\n");  
         print ("</DirectoryEntry>\n");  
     }  
     print ("</CiscoIPPhoneDirectory>\n");  
 ?>  

busqueda.php
 <?php  
 header('Content-Type: text/xml');  
 #DATOS DE CONEXION A LA BASE DE DATOS  
 $mysql_conn = mysqli_connect("IP O FQDN","USUARIO","CONTRASEÑA","BASE DATOS");  
 #VALORES A BUSCAR  
 $NOM = $_GET["nombre"];  
 $resultado = mysqli_query($mysql_conn,"SELECT * FROM contactos WHERE ((nombres LIKE '%$NOM%') AND (tag !='ext')) ORDER BY nombres");  
 $total_resultado = mysqli_num_rows($resultado);  
 if($total_resultado == 0)  
 {  
     print ("\n");  
     print ("<CiscoIPPhoneText>\n");  
         print ("<Title>");  
         print ("Directorio Telefonico");  
         print ("</Title>\n");  
         print ("<Prompt>");  
         print ("No hay coincidencias");  
         print ("</Prompt>\n");  
     print ("</CiscoIPPhoneText>");  
     print ("\n");  
 }  
 else  
 {  
     print ("<CiscoIPPhoneDirectory>\n");  
     print ("<Title>");  
     print ("Directorio Telefonico");  
     print ("</Title>\n");  
     print ("<Prompt>");  
     print ("Coincidencias");  
     print ("</Prompt>\n");  
     while($row = mysqli_fetch_array($resultado))  
     {  
         print ("<DirectoryEntry>\n");  
             print ("<Name>");  
             print ($row['nombres']);  
             print ("</Name>\n");  
             print ("<Telephone>");  
             print ($row['numero']);  
             print ("</Telephone>\n");  
         print ("</DirectoryEntry>\n");  
     }  
     print ("</CiscoIPPhoneDirectory>\n");  
 }  
 ?>  

La base de datos en MySQL, contiene una sola tabla, que llamo directorio, esta tabla contiene 3 columnas: nombres (varchar 35), numero (varchar 15 y PK) y tag (varchar 3). Las dos primeras se explican solas, la ultima sin embargo la coloque para que sea fácil diferenciar de un contacto con varios números (ejemplo, extension local, celular, casa, etc.) Si se fijan en los scripts PHP notaran que en los queries utilizo este campo para distinguir que números mostrar.

domingo, 28 de septiembre de 2014

Cisco 7940G y Asterisk - Parte 2

Continuando con la entrada anterior, en esta ocasión les mostrare como autoconfigurar los teléfonos IP utilizando ficheros cnf y el servidor tftp.

Los teléfonos 7940G, al arrancar luego de descargar las imágenes de software a utilizar (en caso de no tenerlas aun), también descargan una serie de archivos .cnf, estos archivos según su nombre y estructura le indican al teléfono como configurarse, que extensión utilizar, nombre a mostrar en pantalla, aplicaciones (escritas en XML) que el teléfono puede utilizar, etc. 

SIPDefault.cnf

Es el primero de estos archivos, este archivo es común para todos los teléfonos IP, se utiliza para configurar las opciones comunes de todos los teléfonos (ejemplo, hora, fecha, planes de discado, etc.). 

ejemplo de contenido:

 logo_url: "URL del logo a mostrar en la pantalla"  
 directory_url: "URL de la aplicacion de directorio"  
 dial_template: "archivo del plan de discado"  
 date_format: "D/M/Y"  
 sntp_server: "FQDN o IP de servidor sntp"  
 sntp_mode: "unicast"  
 time_format_24hr: "0"  
 time_zone: "EST"  
 dst_offset: "-00:30"  
 dst_start_month: "August"  

Los dos primeros items se utilizan para asignar el logo y aplicación de directorio al teléfono, luego hablare de esto, solo entiendan por ahora que el teléfono descarga via HTTP tanto el logo (en formato bmp) como la aplicación y esta ultima debe estar escrita en XML.

el dial_template indica el nombre del archivo que contiene el plan de discado por el cual se regirá el teléfono, mas abajo encontraran un ejemplo de este plan de discado, todas las demás opciones están puestas de esa forma para colocar el teléfono en la hora estándar de Venezuela que es UTC -4:30, de aquí lo único que deben de cambiar es el FQDN o IP del servidor SNTP (por Internet hay muchas, y si utilizan algún router con esta capacidad pueden utilizarlo a el también como servidor de hora).

Plan de discado 

El nombre de este archivo es indiferente (debe contener la extension xml al final), solo deben tener en cuenta que deben referenciarlo en el parámetro dial_template y lógicamente debe estar en el mismo directorio que todos los archivos de configuración (que al final debe ser el directorio al que se tiene acceso por tftp), al igual que en Asterisk donde existe un plan de discado que indica que hacer según el numero marcado, estos telefonos también pueden tener uno, este plan de discado permite manipular los dígitos marcados, asignarle tonos, invalidar ciertos números, etc...

 <DIALTEMPLATE>  
 <TEMPLATE MATCH="..."      TIMEOUT="2"/>  
     <TEMPLATE MATCH="9*"      TIMEOUT="2"/>  
     <TEMPLATE MATCH="\**"      TIMEOUT="2"/>  
     <TEMPLATE MATCH="04........."  REWRITE="904%1" TIMEOUT="0"/>  
     <TEMPLATE MATCH="02........."  REWRITE="902%1" TIMEOUT="0"/>  
     <TEMPLATE MATCH="2......"    REWRITE="2%1" TIMEOUT="0"/>  
 </DIALTEMPLATE>  

Este plan de discado se basa en el hecho de que en la empresa para realizar llamadas externas se marca primero 9, adicionalmente hay unas reglas de reescritura que utilizo para la integración con el directorio, si quieren pueden utilizar este mismo, provisto que donde vayan a implementar el telefono las extensiones internas tengan 3 dígitos y las llamadas externas comiencen siempre con un 9.

Archivos de configuración por teléfono 

Estos archivos permiten configurar individualmente cada teléfono, asignar una extensión, nombre de usuario, etc. Estos archivos tienen el formato SIP.cnf donde es la dirección mac en mayúsculas y sin separadores (ejemplo, sin ":", "." o "-") del teléfono que se debe configurar, por ejemplo asumiendo que la dirección mac del teléfono es  ca:da:11:22:33:44 el archivo de llamaria SIPCADA11223344.cnf


 proxy1_address: "FQDN o IP del proxy (Asterisk)"  
 line1_name: "nombre de la extensión"  
 line1_shortname: "Nombre a mostrar en la pantalla del teléfono"  
 line1_displayname: "Caller ID"  
 line1_authname: "usuario para autenticar"  
 line1_password: "contraseña"  
 nat_enable: "0"  
 proxy_register: "1"  

Todos los items se explican por si mismo, excepto quiza line1_authname, aqui deben colocar el nombre con el que registraron la extensión para autenticarla, es lo que se encuentra entre corchetes [] cuando definen la extensión en el SIP.conf. Adicionalmente, nat_enable en 0 indica que los teléfonos no trabajaran utilizando NAT (chequeen esto si quieren saber mas), y proxy_register en 1 indica que el teléfono debe registrarse con el proxy utilizando los parámetros antes descritos para poder realizar o recibir llamadas.

Si quieren conocer mas sobre los parametros de configuracion de los telefonos 7940G con SIP, chequeen el siguiente enlace:

Guía de administración SIP Cisco

Parte 3 de la guia

sábado, 27 de septiembre de 2014

Cisco 7940G y Asterisk - Parte 1

Recientemente me toco reformar el sistema telefónico de la compañía para la que trabajo, en una de las sedes se tiene implementado un "todo-en-uno" de Cisco (UC-520), este aparato incluye central telefónica, router, switch y gateway vpn,

Si bien en esa sede todo funciona correctamente con el UC-520, para la nueva sede se requería de una infraestructura mas expandible y que pudiese albergar mas usuarios de los que el UC-520 permite, adicionalmente aquí había una limitante a nivel monetaria, adquirir alguna solución telefónica de Cisco implicaba un desembolso considerable de dinero, así que me fui por la opción libre, Asterisk,

Asterisk trabaja principalmente con el protocolo SIP, así que a parte del servidor donde se instalaría y las tarjetas de interconexion PSTN (para poder ofrecer conectividad a redes telefónicas  externas), se necesita también de teléfonos IP compatibles con este estándar. Resulta que cuando la empresa adquirió el UC-520, también compro una gran cantidad de teléfonos IP Cisco 7940G, muchos mas de los que eran utilizados para ese entonces.

Para los que no lo sepan, estos teléfonos de fabrica trabajan es con un protocolo propietario de Cisco llamado SCCP, así que no me servían para trabajar con Asterisk, sin embargo investigando un poco encontré que Cisco hace unos cuantos años libero imagenes del software del teléfono compatibles con el estándar SIP, esta entrada es principalmente para indicarles como transformar los 7940G con la imagen SCCP a teléfonos compatibles con SIP, en proximas entradas les mostrare como configurarlos y adicionalmente integrarlos en un directorio telefónico interno centralizado.

Proceso de cambio de firmware

Vamos a necesitar:

1.- Obviamente el teléfono Cisco 7940G
2.- El servicio DHCP y TFTP
3.- El pack de imágenes de software SIP, van a necesitar los archivos (pueden descargarlos desde aqui):

      P003-8-12-00.bin
      P003-8-12-00.sbn
      P0S3-8-12-00.loads
      P0S3-8-12-00.sb2
      OS79XX.TXT
      cmterm-7940-7960-8.2.00-sip.cop

4.- Un archivo que llamaran "XMLDefault.cnf.xml" (notese que tiene 2 extensiones) y donde copian y pegan lo siguiente:

 <Default>  
 <callManagerGroup>  
 <members>  
 <member priority="0">  
 <callManager>  
 <ports>  
 <ethernetPhonePort>2000</ethernetPhonePort>  
 <mgcpPorts>  
 <listen>2427</listen>  
 <keepAlive>2428</keepAlive>  
 </mgcpPorts>  
 </ports>  
 <processNodeName></processNodeName>  
 </callManager>  
 </member>  
 </members>  
 </callManagerGroup>  
 <loadInformation8 model="IP Phone 7940">P0S3-8-12-00</loadInformation8>  
 <loadInformation7 model="IP Phone 7960">P003-07-1-00</loadInformation7>  
 <authenticationURL></authenticationURL>  
 <directoryURL></directoryURL>  
 <idleURL></idleURL>  
 <informationURL></informationURL>  
 <messagesURL></messagesURL>  
 <servicesURL></servicesURL>  
 </Default>  

Configuración servicio TFTP

En mi caso, el servicio TFTP radica en un servidor Linux corriendo CentOS, si tienen esta distribución instalada para poder activar el servicio TFTP básicamente editamos el archivo tftp, ubicado en /etc/xinetd.d/ para que nos quede así:

 service tftp  
 {  
     disable = no  
     socket_type       = dgram  
     protocol        = udp  
     wait          = yes  
     user          = user  
     server         = /usr/sbin/in.tftpd  
     server_args       = -c -s /tftp-directory  
     per_source       = 11  
     cps           = 100 2  
     flags          = IPv4  
 }  

Donde "/tftp-directory" es la ruta del directorio que piensan utilizar para almacenar los archivos que serán descargados por el teléfono mediante tftp (guarden aqui los archivos que les especifique arriba) y "user" el usuario como quieren que se ejecute el servicio. Luego de esto sencillamente escribimos en la consola "service xinetd restart".

Configuración servicio DHCP

El servicio DHCP corre actualmente en un servidor con Windows Server 2012r2, así que también aproveche este para poder realizar este trabajo, deben es asegurarse de crear un scope (ambito) para los teléfonos IP (con un rango de IP validos, gateway, dns, etc) y dentro de este scope se necesita agregar adicionalmente la opción 150, la cual por defecto no se incluye en el servicio DHCP asi que se debe crear, para crear esta opción realizamos lo siguiente:

1.- Nos vamos al administrador del servicio y presionamos sobre "IPv4" con el botón derecho del mouse,
2.- En el menu desplegable presionamos sobre "Configurar Opciones Predeterminadas..."
3.- En el cuadro que nos aparece presionamos "Agregar".
4.- Nos aparece otro cuadro donde debemos llenar los parámetros de la opción, aquí lo importante es que el tipo de dato sea "Dirección IP" y el código "150".


Asegúrense de que cuando configuren la opción en el ambito, apunte directamente al servidor donde funciona el servicio TFTP (en mi caso en el server que corre CentOS). 

Nota:

Estos pasos son como yo termine realizado el trabajo, sin embargo si no quieren hacerlo tal cual,, lo único que necesitan es tener el servicio TFTP y DHCP funcionando, el servicio TFTP debe tener acceso a los archivos que arriba describo y el servicio DHCP debe estar configurado para adicional a los parámetros básicos (ip, mascara, gateway, etc.) incluya la opcion 150 que apunte al servidor donde corre el servicio TFTP, hay una aplicacion para windows que incluye ambos servicios se llama TFTPD32. En mi caso lo realice de esta forma porque asi puedo sencillamente conectar un telefono a la red y ya se que todo esta preparado para que se actualice a SIP y descargue la configuracion de la linea a utilizar (mas adelante hablo sobre esto). 

Lógicamente deben asegurarse que el teléfono descargue su configuración del server DHCP, ya sea colocando el teléfono dentro del mismo segmento L2 que el servidor o utilizando un DHCP Relay. Recuerden que estos telefonos al ser Cisco, se pueden comunicar con equipos Cisco mediante CDP y obviamente son compatibles con la asignación de VLAN de voz mediante el comando "switchport voice vlan XXX".

Si han hecho todo bien, cuando conecten el teléfono a la red y lo enciendan, este comenzara a descargar los archivos del servidor TFTP luego de configurar su IP, si funciono, al final verán que el teléfono en la esquina superior derecha dice "UNPROVISIONED SIP", si no dice esto, algo hicieron mal, verifiquen todo y comiencen de nuevo.

Actualización: si por alguna razón, el teléfono se niega a descargar las imágenes del software para trabajar con SIP y en pantalla les coloca "SEP.xml.cnf file not found", lo que tienen que hacer es crear ese archivo y colocarlo en la raiz del servidor tftp, el contenido de este archivo debe ser el mismo que coloco arriba para el XMLDefault.xml.cnf.

Continua en: Parte - 2




jueves, 19 de junio de 2014

DHCP y NAT

   Todos conocemos de cierta forma el funcionamiento de DHCP y de las traducciones de dirección de red (NAT). NAT es ampliamente utilizado hoy día para tratar de reducir el ritmo en el cual se agotan las direcciones IP enrutables públicamente (en la versión 4 del protocolo IP), es decir, las direcciones IP utilizadas en Internet, aunque NAT no solo se utiliza para lo anterior, también puede ser aplicado en estos casos:


  1. Migración de servidores, dado que es mas fácil y rápido realizar un NAT a los paquetes cuando se migra un servidor de un segmento de red a otro que tener que decirle manualmente a cada estación de trabajo la nueva dirección IP de este, y aun si utilizamos DNS, dependemos enteramente del TTL, lo cual evita que la transición sea transparente y rápida si no se sincroniza este parámetro, por ello se suele hacer uso de NAT para estos casos.
  2. Seguridad, a veces sencillamente no se desea que se conozca el o los segmento(s) de red detrás del router que realiza NAT. 

   DHCP por otro lado, evita que tengamos que configurar manualmente cada estación de trabajo, automatiza enormemente la asignación de direcciones de red y parámetros asociadas a estas, también habilita la autoconfiguración de servicios (como es el caso de los teléfonos IP). Normalmente nos encontramos con 2 casos de implementacion de servicio DHCP.

Caso nº 1

 El servidor DHCP, que puede ser tanto un servidor como un router, se encuentra dentro del mismo segmento de red que los equipos a los que va a servir, como se muestra a continuación: 



  En el caso anterior, no hay problemas, todo funciona correctamente con una configuración mínima. 

Caso nº 2

   El servidor DHCP no se encuentra dentro del mismo segmento de red que la red a la que sirve: 



   En este caso se soluciona haciendo uso de un DHCP-Relay Agent, el cual es un intermediario, que se comunica de parte del cliente que hace la solicitud con el servidor DHCP por medio de mensajes UNICAST, recordemos que DHCP funciona normalmente es con mensajes Broadcast. Esto tampoco tiene mayor inconveniente mas allá de configurar el relay que puede ser el mismo router que sirve de gateway a la LAN que solicita el servicio. 

Caso nº 3

   Básicamente casi igual al anterior, pero, antes del enlace con el DHCP Server se realiza un NAT. En este caso, notaremos que por mas que configuremos el Relay, los dispositivos que solicitan el servicio DHCP no obtienen respuesta, todo parece estar bien, se tiene conectividad con el DHCP Server, verificado mediante ICMP con algún dispositivo de la LAN que solicita el servicio configurado manualmente. Entonces, ¿cual es el problema?

   Recordemos lo siguiente, NAT traduce direcciones en el caso de un Source-NAT que suele ser lo habitual, se traduce la IP de origen a otra, tenemos entonces el siguiente caso:
  1. 192.168.0.1 se quiere comunicar con 10.10.10.1.
  2. El host A, quien es el que posee la dirección 192.168.0.1, esta detrás de un NAT, esto implica que cuando quiere comunicarse con 10.10.10.1, lo que el host B (el propietario de 10.10.10.1) "ve" como dirección de origen no es la IP del host A, sino la IP que fue asignada producto de la traducción. 
  3. Hasta aquí todo bien, de no ser por como funciona DHCP por medio de un Relay tendríamos conectividad.

   Cuando se hace uso de un DHCP-Relay, este, dentro del mensaje DHCP envía un parámetro llamado GIADDR, este parámetro es la dirección IP de la interfaz que intercepto el paquete DHCP, el proceso es el siguiente:

  1. Host A, quiere configurarse con DHCP, el segmento de red es 192.168.0.0/24, para esto, envía un mensaje DHCP-Discover en forma de broadcast, tal cual el protocolo lo estipula. 
  2. Dentro de ese segmento, se encuentra el relay, cuya dirección IP es 192.168.0.1, este intercepta el broadcast y envía el mensaje como unicast a la dirección del servidor DHCP, incluyendo adicionalmente en el campo GIADDR la dirección IP 192.168.0.1/24 la cual es la dirección de la interfaz que intercepto el primer broadcast, luego en la cabecera IP incluye como dirección de origen, la dirección 192.168.0.1. 
  3. Durante el trayecto hasta el servidor DHCP, ocurre un NAT, ahora la dirección IP de origen del mensaje anterior no es 192.168.0.1, sino la asignada por el NAT (diremos que es 201.202.203.1 en este caso). 
  4. Cuando el servidor DHCP recibe el mensaje, se fija en los parámetros internos de este, en especifico el GIADDR dado que este parámetro es el que se toma como referencia para elegir el pool de direcciones IP de donde se asignara la dirección al host, recordemos que en este caso es 192.168.0.1/24.
  5. Y aquí es donde viene el problema, el servidor DHCP no se va a fijar en la dirección IP de origen de la cabecera IP para responder el mensaje, sino que directamente utiliza la dirección IP incluida en GIADDR para responder, si, el o los routers que intervienen en el camino desde el server DHCP al relay, no conocen la forma de llegar a la red que se estipula en GIADDR, lo cual suele ser lo habitual si se utiliza NAT, el paquete jamas llegara de vuelta y por lo tanto los equipos jamas se podrán autoconfigurar. 

  Para solucionar esto se pueden hacer unas cuantas cosas:
  • Aplicar enrutamiento basado en políticas y túneles IP/IP (GRE), de esta forma cuando detectemos el trafico generado por DHCP-Relay, que se maneja por protocolo UDP puertos 67 y 68, obligamos al router a utilizar como next-hop el tunel IP/IP, este encapsulara el paquete original en otro paquete IP y no realizara NAT, se debe realizar esto por norma general en el router que realiza el NAT.
  • Utilizar túneles IPSec
  • Utilizar una combinación de lo anterior, ejemplo, GREoIPSec.
  • Crear rutas especificas a las redes que solicitan el DHCP, algo inútil en el caso de que la red intermediaria sea Internet y que adicionalmente elimina el propósito de NAT si se utiliza como mecanismo de seguridad.