martes, abril 25, 2017

Comprobando la conectividad entre máquinas para evitar problema de firewall

En ocasiones necesitamos comprobar a un nivel muy elemental que cierto puerto o servicio está disponible entre máquinas. Puede ser que falle el servicio, el firewall de la máquina, el firewall de tu infraestuctura si dependes de un tercero...

Lo más habitual es que para comprobar que cierto servicio está disponible desde tu red uses un nmap que suele dar el resultado que necesitas.

$ nmap -p 80 xxx.xxx.xxx

Starting Nmap 7.01 ( https://nmap.org ) at 2017-04-25 14:38 CEST
Nmap scan report for xxx.xxx.xxx (yyy.yyy.yyy.yyy)
Host is up (0.0078s latency).
PORT   STATE SERVICE
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 0.15 seconds

En muchas ocasiones intento hacer también un telnet directo al puerto en cuestión para ver si además del puerto el servicio está disponible

$ telnet yyy.yyy.yyy.yyy 53
Trying yyy.yyy.yyy.yyy...
Connected to yyy.yyy.yyy.yyy.
Escape character is '^]'.

Pero te puede pasar, como ha sido mi último caso, que las reglas de firewall te traicionen y aunque aparentemente el puerto esté abierto, las respuestas no puedan volver. En mi caso era un servidor de DNSmasq que funciona sobre paquetes UDP. En local funcionaba correctamente, en la red de servidores funcionaba correctamente, pero no conseguía responder desde la red desarrollo. Todos los puertos parecían correctamente abiertos y como se ve en ejemplo anterior el telnet respondía ¿Qué estaba pasando?

Pues pasaba que el firewall no permitía que los paquetes UDP (protocolo usado por el DNS) volvieran a la red de desarrollo. ¿cómo pude darme cuenta? Con el comando netcat, una especie de navaja suiza de la conectividad TCP/IP aún más "básica" que telnet.

Puedes probarla con cualquier servidor web:

$ netcat www.google.com 80
GET /

...y el servidor de google te responderá.

Pero la clave es que la puedes usar en tus dos máquinas para crear una comunicación cliente/servidor sencilla con el protocolo que quieras para que ambas máquinas "dialoguen" en un formato de texto plano. Como hacer un chat a nivel muy muy básico.

Probando que dos máquinas se pueden comunicar a través del puerto 890 por TCP:

En  la máquina servidor pongo a escuchar el netcat:

# netcat  -l -p 890

En la máquina cliente conecto al puerto correspondiente del servidor

$ netcat yyy.yyy.yyy.yyy 890

En ambos casos el cursor se queda esperando la siguiente instrucción. Si escribo "hola" en el cliente y la comunicación puede fluir, la palabra aparecerá en el servidor. Si escribo algo en el servidor pasará lo mismo en el cliente.

Con este comando comprobé que ambas máquinas se podían comunicar correctamente a través del protocolo TCP pero cuando lo intenté con el protocolo UDP...

# netcat  -u -l -p 890

$ netcat -u yyy.yyy.yyy.yyy 890

... vi que los mensajes sí que llegaban desde el cliente al servidor pero no los del servidor al cliente. Así pues contacte con el administrador de redes de mi infraestructura para que verificara. Efectivamente, el tráfico UDP de retorno estaba filtrado. Una vez resuelto el "dialogo" UDP funcionaba correctamente y el servicio de DNS también.






viernes, julio 29, 2016

Programar el apagado de un servidor ubuntu linux para una fecha / hora específica

Programar el apagado de un servidor ubuntu linux para una fecha / hora específica es muy sencillo desde la terminal.

El comando shutdown permite directamente programar el apagado para una hora específica con:

$shutdown now 18:30

...o dentro de un tiempo específico con:

$shutdown now +15 (en 15 minutos)

Pero si quieres apagar el servidor en un día y hora específicos sin tener que tocar el CRON hay una herramienta muy útil "at"

#apt-get update && apt-get install at
#echo "shutdown now" | at 10pm Aug 4

Ejecutará el comando indicado a la hora y fecha indicadas, simple y efectivo. Eso sí, asegúrate de tener los permisos para hacerlo. Este comando lo lancé de la cuenta de root ($sudo su)

miércoles, junio 08, 2016

Generando un listado html a partir de una lista de archivos con RegEX

Si tienes un editor que realice búsquedas y sustituciones con expresiones regulares como Atom.io o lo haces directamente con SED, tal vez te interese esta pequeña chuleta para generar un html específico partiendo de una lista plana de archivos como la que puedes generar con un ls.

Ejemplo de lista plana de archivos
2008 AM.jpg
2008-0.jpg
AM 2 2010.jpg
AM 3 2010.jpg
AM 2008-0.jpg
AM 2008-1.jpg

Expresión regular para detectar
(.*) -> toda secuencia de letras que no sea un salto de línea

Patrón de sustitución
<div class="pin">
  <a href="img/biografia/$&" data-toggle="lightbox" data-gallery="multiimages">
    <img src="img/biografia/$&" />
  </a>
</div>

Resultado
<div class="pin">
  <a href="img/biografia/2008 AM.jpg" data-toggle="lightbox" data-gallery="multiimages">
    <img src="img/biografia/2008 AM.jpg" />
  </a>
</div>
<div class="pin">
  <a href="img/biografia/2008-0.jpg" data-toggle="lightbox" data-gallery="multiimages">
    <img src="img/biografia/2008-0.jpg" />
  </a>
</div>
<div class="pin">
  <a href="img/biografia/AM 2 2010.jpg" data-toggle="lightbox" data-gallery="multiimages">
    <img src="img/biografia/AM 2 2010.jpg" />

  </a>
</div>
...

jueves, mayo 26, 2016

Servidor web Apache2 rechazar peticiones a la IP y no al dominio

Es frecuente que tenga varios dominios alojados en el mismo servidor web y que por "higiene" no quiera que el servidor responda cuando hagan una petición directamente a la dirección IP (tipo http://xxx.xxx.xxx.xxx). Por defecto Apache2 suele redirigir las peticiones al primero de los sites configurados pero en mi caso es una solución que no me termina de gustar. Después de rebuscar un poco por Internet parece ser que no se pueden rechazar las peticiones a no ser que te bajes a muy bajo nivel de comunicaciones.

El truco más sencillo es crear un VirtualHost que use como ServerName la dirección IP y devolver un error 403 Forbbiden. Rápido y fácil.

$sudo nano /etc/apache2/sites-available/reject-by-IP.conf

<VirtualHost *:80>
    ServerName xxx.xxx.xxx.xxx <- IP de tu servidor
    <Location />
        Order allow,deny
        Deny from all
    </Location>
</VirtualHost>


$sudo a2ensite reject-by-IP.conf
$sudo service apache2 reload


Ahora al intentar acceder a la IP obtendrás un error como este:


lunes, marzo 21, 2016

Usando Docker para crear máquinas virtuales ubuntu debian para testing - Crear una imagen a medida

En la anterior entrada sobre docker ya me llevé una grata sorpresa de cómo descargar y usar una imagen limpia de Ubuntu 14.04 en unos segundos con que la poder testear un script para la compilación de las últimas versiones de libgphoto2.

El principal problema era que en cada ocasión tenía que instalar git en el contenedor descargado y posteriormente clonar el proyecto git con su rama correspondiente y lanzar manualmente el script. Dado que además quería probar el script en Debian 7 y 8 resultaba en que tenía que hacer muchas acciones manuales.

He  tenido tiempo de sentarme a mirarlo con más detenimiento y resulta muy fácil crear una imagen personalizada partiendo de una base oficial como ubuntu o debian a la que posteriormente puedo añadir una serie de comandos personalizados para que agilice la ejecución.

El objetivo es que finalmente se me quede un único script en el que yo pueda ejecutar  "probar-en [SO deseado] [direccion de la rama git que quiero probar]". En cada ocasión el contenedor será una imagen limpia de ubuntu/debian/raspbian que sólo tendrá instalado git.

Empezamos creando la imagen personalizada de Ubuntu 14.04 con los añadidos para ejecutar los tests. Lo hacemos en dos pasos:
  • Crearmos un dockerfile, que especifica las características de la imagen que queremos crear y generándola
  • Añadimos la funcionalidad para que descargue la rama y la ejecute
Creando el container básico
Creamos una carpeta específica para el proyecto y dentro de ella un archivo llamado "Dockerfile" con el siguiente contenido indicando cual es la imagen base que vamos a tomar y el añadido que le queremos ahcer


   FROM ubuntu:14.04
   RUN apt-get -y update && apt-get install -y git

Guardamos y generamos la imagen con 

   docker build -t ubuntu-14.04-git .

El nombre ubuntu-14.04-git será el nombre de la imagen que figurará en nuestros respositorio local. Una vez finaliza la ejecución podemos comprobar que se ha generado correctamente con:

   $ docker images
   REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
   ubuntu-14.04-git    latest              d9adeb8df631        21 minutes ago      247.5 MB

Si accedemos a la imagen con "docker run -ti ubuntu-14.04-git /bin/bash" accederemos a la línea de comandos y podremos comprobar que es una imagen limpia con el git recien instalado.

Añadiendo el script de descarga y compilación
En mi caso quiero que el container este listo para que con un sólo comando se descargue un repositorio git y ejecute el script correspondiente. Así pues voy a crear un script de shell que haga todo eso para copiarlo dentro del container y que se ejecute al lanzarlo. 

En la misma carpeta donde tenemos el Dockerfile añadimos un fichero llamado test-script.sh con el siguiente contenido:

   #!/usr/bin/env bash
   git clone $1
   cd gphoto2-updater
   ./gphoto2-updater.sh

Como puedes ver es bastante obvio lo que hacer: recibe por parámetro una URL de un repositorio git, lo descarga, accede a la carpeta y lanza el comando.

Modificamos el Dockerfile con el siguiente contenido:

   FROM ubuntu:14.04
   RUN apt-get -y update && apt-get install -y git
   COPY ./test-script.sh /

... y generamos de nuevo la imagen para que añada el fichero al sistema de archivos...

   docker build -t ubuntu-14.04-git .

tardará sólo un momento y la imagen estará lista para trabajar. Cada vez que quiera probar una nueva rama de mi script basta con que lance:

   docker run -rm -ti ubuntu-14.04-git /test-script.sh [URL de la rama GIT para probar]

...y tendré un container limpio de ubuntu 14.04 con el git instalado que directamente descargará la rama git indicada y lanzará el script de compilación. Una vez finalice saldrá y el flag rm borrará el container que se acababa de generar sin que queden rastros de la ejecución. 

En mi caso he creado una alias para el comando anterior en el que reduzco el comando a 

   $test-ubuntu.sh [url proyecto git]

Partiendo de esta base es muy sencillo crear imágenes similares para debian 7 y 8 e incluso un script genérico para que lance los test sobre todos los SO que quiera.

Creando un dockerfile para cada SO
Muy sencillo, podemos crearlos todos en la misma carpeta añadiendo un sufijo al Dockerfile (como por ejemplo Dockerfile-debian-7) y luego personalizamos la llamada al docker build como sigue:

   docker build -t debian-7-git -f Dockerfile-debian-7 .

Generará una imagen con la etiqueta debian-7-git. Ahora sí, revisando los alias puedo lanzar el testing de un rama GIT sobre un SO limpio con algo tan simple como:

   $ ./test-os.sh debian-7-git https://github.com/gonzalo/gphoto2-updater.git
   $ ./test-os.sh debian-8-git https://github.com/gonzalo/gphoto2-updater.git
   $ ./test-os.sh ubuntu-14.04-git https://github.com/gonzalo/gphoto2-updater.git
   $ ./test-os.sh raspbian-8-git https://github.com/gonzalo/gphoto2-updater.git





lunes, marzo 07, 2016

Cómo importar contactos con télefono a Google Contacts con excel o csv

El otro día tuve que crear una cuenta de Google Contacts a la que necesitaba importar unos 400 contactos con teléfono que me habían pasado en una excel. El tema era más delicado de lo que parecía y no conseguía que identificara correctamente los teléfonos como tales.

Resulta que el importador de contactos de Google no es demasiado avanzado y exige que uses una plantilla muy concreta para poder recoger los contactos correctamente, aunque es sencillo adaptar tu documento para poder hacerlo.

Basta con crear una hoja de cálculo que has de guardar en formato csv. Te sugiero al guardar el csv indiques que los campos te los encierre con "" y como separador de campos uses la coma (,). Los nombres de las columnas deben ser obligatoriamente los siguientes y tienen que estar en inglés:

  • name
  • notes (opcional, por si quieres poner notas)
  • Phone 1 – Type
  • Phone 1 – Value
El valor de la columna "Phone 1 – Type" tiene que ser algo como "Mobile" aunque también puedes cambiarlo por "Work" o "Home"... cualquiera de los valores que acepte la ficha de Google Contatcs.
En el campo "Phone 1 – Value" pones el número de teléfono preferentemente precedido del código de país (+34 en España) para que pueda gestionarlo mejor.


Si necesitas añadir más campos aquí tienes una guía de todas las etiquetas que reconoce Google Contacts. Aunque dicha lista parece ser que varía con cierta frecuencia.

Ahora para importar te vas a la página principal de los contactos. Pinchas en "Más"->Importar->desde csv y le pasas el archivo que has generado.