Remover direcciones IP bloqueadas por DenyHosts

January 25th, 2009

DenyHosts es un script escrito en Python que analiza los logs del servidor sshd y determinar posibles intentos de ataques. En caso de que se detecte tal intento se actualiza el archivo /etc/hosts.deny con la IP del posible ataque para prevenir cualquier intento futuro.

A través del archivo /etc/denyhosts.conf se setea la configuración, por ejemplo cantidad de intentos fallidos por el puerto ssh (por defecto 22) para que se considere un ataque.

¿Qué sucede si por equivocación DenyHosts nos confunde con un atacante al habernos confundido en la cantidad de intentos posibles? Nuestra IP es almacenada en /etc/hosts.deny y por lo tantos tenemos el acceso bloqueado. Para remediar esta situación no bastará con remover nuestra IP de hosts.deny. Tenemos que hacer lo siguiente:

  • Detener DenyHosts (i.e. /etc/init.d/denyhosts stop)
  • Remover la IP bloqueada de /etc/hosts.deny
  • Remover la IP bloqueada de WORK_DIR/hosts
  • Remover la IP bloqueada de WORK_DIR/hosts-restricted
  • Remover la IP bloqueada de WORK_DIR/hosts-root
  • Remover la IP bloqueada de WORK_DIR/hosts-valid
  • Remover la IP bloqueada de WORK_DIR/user-hosts
  • Arrancar DenyHosts (i.e. /etc/init.d/denyhosts start)

Nota: Para obtener WORK_DIR utilizar el siguiente comando:


$ cat /etc/denyhosts.conf | grep 'WORK_DIR ='

En Debian Etch la salida del comando anterior es WORK_DIR = /var/lib/denyhosts

Fuente

Normalizando paths

January 16th, 2009

Básicamente normalizar un path consiste en remover todas las ocurrencias ‘..’ y ‘.’ para obtener un path absoluto. Por ejemplo, si tenemos: /foo/bar/../baz, normalizado quedaría /foo/baz.

Podemos hacer una sencilla función de normalización en Ruby con la ayuda de expresiones regulares. Por ejemplo:


def normalizar path
  ret = path.split(%r{/\.(/|\Z)}).join
  ret = ret.split(%r{/[^/]+/\.\.}).join
  raise “path incorrecto” if %r{/\.\.(/|\Z)} =~ ret ||
                                      ret[0] != ?/
  ret
end

Expliquemos que hace cada línea:

  • path.split(%r{/\.(/|\Z)}).join; remueve todas las ocurrencias ‘.’ del path.
  • ret.split(%r{/[^/]+/\.\.}).join; remueve todas las ocurrencias ‘..’ del path.
  • %r{/\.\.(/|\Z)} =~ ret || ret[0] != ?/; larga una excepción en caso de que se ingrese un path que no pueda ser normalizado. Verifica que el primer caracter del path sea ‘/‘ y que no se tengan situaciones como ‘/../foo‘.

Dejo un par de ejemplo de prueba:


irb(main):002:0>  normalizar "/foo/../bar/."
=> "/bar"
irb(main):003:0> normalizar "/foo/./bar/../baz"
=> "/foo/baz"
irb(main):004:0> normalizar "./foo/./bar/../baz"
RuntimeError: path anormal `./foo/./bar/../baz'
        from (irb):4
irb(main):005:0> normalizar "../foo/"
RuntimeError: path anormal `../foo/'
        from (irb):5
irb(main):006:0> normalizar "/../foo/"
RuntimeError: path anormal `/../foo/'
        from (irb):6

Pueden probar los ejemplos online desde aquí: http://www.rubular.com/

Son bienvenidos aportes y comentarios :-)

Restringir edición a usuarios anónimos

December 9th, 2008

Solamente hay que agregar en el archivo LocalSettings.php (válido para versiones 1.5 y superiores):


$wgGroupPermissions['*']['edit'] = false;

Referencia

Valores por defecto para argumento hash

December 4th, 2008

Cuando un método requiere varios argumentos puede resultar difícil recordar el orden en que deben ser pasados. Es por esto que algunos lenguajes permiten invocar métodos a través de nombres de parámetros y sus valores. Ruby no soporta esa forma, pero se puede obtener, el mismo resultado, a través del uso de un hash en el argumento.

Buscando encontré esta estupenda forma de establecer valores por defecto en un hash, de manera de obtener argumentos opcionales en la invocación.


def foo args
  args[:unidad] ||= 0
  args[:total] ||= 1
  args[:unidad] / args[:total]
end

>> foo :unidad => 23
=> 23
>> foo :total => 12
=> 0

Referencia

Imprimir PDF: dos páginas por hoja y doble faz

December 3rd, 2008

Recurrente problema que he tenido hace tiempo; además de ser una manera excelente de economizar en impresiones de libros digitales.

Simplemente he codificado un pequeño script que divide el documento en cuestión en dos archivos: primeras.pdf y segundas.pdf. Cada archivo contiene las hojas divididas, teniendo en cuenta que se van a imprimir dos hojas por cara, para primero imprimir todas las hojas correspondientes a las caras superiores y el otro el de las inferiores.

Por ejemplo: tenemos un documento llamado libro.pdf el cual tiene 16 hojas. Al utilizar el script obtendremos dos archivos, los cuales contendrán las hojas:

  • primeras.pdf; contiene hojas de las caras superiores: 1, 2, 5, 6, 9, 10, 13, 14.
  • segundas.pdf; contiene hojas de las caras inferiores: 3, 4, 7, 8, 11, 12, 15, 16.

Script


#!/bin/bash
total=#Coloque la cantidad de hojas del documento
eval pdftk A=$1 cat `i=1;while [ $i -lt $((total)) ];
do echo A$i A$(($i+1));
let i=$(($i + 4));
done` output primeras.pdf
eval pdftk A=$1 cat `i=3;while [ $i -lt $((total)) ];
do echo A$i A$(($i+1));
let i=$(($i + 4));
done` output segundas.pdf

Uso

  1. Hay que editar el script (como se indica más abajo).
  2. Colocar el documento en la misma carpeta que el script.
  3. Abrir una terminal y teclear:
    
    $ ./script.sh foo.pdf
    
  4. Genera dos archivos. Primero imprimir: primeras.pdf, luego segundas.pdf.

Consideraciones

  • Para que el script funcione se debe tener instalado pdftk; un pequeño software que manipula documentos PDF (en cualquier distribución Debian: aptitude install pdftk).
  • Lamento no ser un experto en bash; el script no es perfecto. Antes de utilizarlo hay que indicarle la cantidad de hojas del documento, editando el script, asignando el valor a la variable: total. He intentado automatizar esto pero no he podido lograrlo. Si alguien lograse hacerlo agradecería que compartiese la solución. (dejo una pequeña ayuda para obtener la cantidad de hojas del documento PDF: eval pdftk $documento dump_data | grep “NumberOfPages:” | awk ‘{print $2}’).

Subversion y Squid

August 13th, 2008

Trabajando en un proyecto, que lo tengo administrado bajo un repositorio en Subversion, me encontré con problemas al momento de realizar commit, vía web, de los cambios.

Obtenía el siguiente mensaje de error.


$ svn ci -m "cambios"
svn: Falló el commit (detalles a continuación):
svn: MKACTIVITY de '/svn/repos/projectNew/!svn/act/0a63fbb4-16d4-40b1-bc87-2f0dbd0eb709': 400 Bad Request (http://192.168.6.3)

Después de muchos idas y vueltas, pude hacerme con la solución. El problema surge de que el servidor de Subversión se encuentra detrás de un proxy web, específicamente un Squid, por lo tanto, cuando el cliente de Subversion se comunica con el servidor Subversion (vía HTTP), utiliza una serie de métodos que no eran interpretados por el proxy. Los métodos en cuestión pertenecen a un subconjunto del los métodos añadidos al HTTP por WebDAV.

Entonces, para poder solucionar esto, tendríamos que lograr que Squid interprete estos métodos. Por defecto, Squid no los interpreta pero los soporta, de modo que, tendremos que editar la configuración para indicárselo.


#  TAG: extension_methods
#       Squid only knows about standardized HTTP request methods.
#       You can add up to 20 additional "extension" methods here.
#
#Default:
# none
extension_methods REPORT MERGE MKACTIVITY CHECKOUT

Nota: Lo que está encerrado en rectángulo rojo es la configuración que debe ser agregada al archivo.

Una vez guardado los cambios, se debe reiniciar el servicio (/etc/init.d/squid force-reload) para que Squid tomé los cambios en la configuración.

Ahora si volvemos al cliente y probamos el commit no debería dar problemas


$ svn ci -m "cambios"
Enviando       informe/001.tex
Enviando       informe/002.tex
Enviando       informe/003.tex
Transmitiendo contenido de archivos .......
Commit de la revisión 87.

Referencias

Problemas con imágenes en MediaWiki

August 7th, 2008

El otro día al administrar un wiki, potenciado por MediaWiki, me encontré con un problema con la visualización de imágenes, subidas en el servidor, cuando eran insertadas en artículos. Comentó cómo solucioné esto.

Al insertar una imagen muy grande o cuando la reducía me lanzaba el siguiente error.


Error al crear miniatura: /var/www/wiki/bin/ulimit4.sh: line 4: /usr/bin/convert: No such file or directory

Resumiendo, el error surgía al intentar hacer alguna transformación sobre la imagen (e.g. agrandar, reducir, etc.), sumando esto a lo descripto por el error, estaba faltando instalar algún programa que se encarga de esta tarea.

Investigando un poco, el comando convert está disponible en el paquete imagemagick en Debian. Al verificar en el servidor que corría el wiki, sobre ese paquete, efectivamente imagemagick no estaba instalado; bastó hacer un aptitude install imagemagick.

Una vez instalado volví al wiki y pude verificar que la imagen se visualizaba perfectamente.

Fuentes

Imágenes en Latex

July 25th, 2008

Lograr ser un Latexperto es difícil más aún con el uso de imágenes en documentos, debido al peculiar tratamiento de estas por Latex. Gran parte del problema es que las imágenes (por ejemplo una con formato PNG) son objetos que no interpreta Latex, por estar en un “lenguaje” no comprensible por él. De modo que al incluir imágenes surgen problemas al integrarse con el flujo del documento y es cuando la experiencia empieza a jugar su rol en el desarrollo de documentos de calidad.

En Latex podemos utilizar el paquete graphicx para insertar gráficos y manipularlos. Por lo tanto, gran parte de la experiencia que comentaba requiere conocimientos sobre el uso de este paquete.

Aquí presentaré un par de ejemplos para incorporar imágenes PNG a un documento y otras cosas más.

Cuando incluimos el paquete graphicx a nuestro documento lo importante es determinar correctamente el controlador con que será cargado ¿Qué es el controlador? El controlador es el encargado de visualizar la imagen en nuestro documento. Cuál controlador elegir depende de qué formato de imágen vayamos a insertar. A continuación presento una lista (no exhaustiva) de controladores.

pdftex
Este controlador acepta los formatos: JPEG, TIF, TIFF, PNG y PDF.
dvips
Acepta los formatos: PS, EPS, PCX y BMP.

Veamos como queda el comando usepackage si queremos utilizar graphicx especificando un controlador para imágenes en formato PNG:


\usepackage[pdftex]{graphicx}

Ahora falta incluir el gráfico en el documento, supongamos que el documento fuente se encuentra en /home/user/src/trabajo/ y creamos una carpeta donde alojamos las imágenes PNGs en /home/user/src/trabajo/images/ . Entonces para incluir la imagen utilizamos el comando


\includegraphics{images/foto0839.png}

Nota: Al definir la ruta de la imagen incluida utilicé una ruta relativa ya que la carpeta images se encuentra bajo trabajo y es ésta la que aloja el fuente .tex

Presento un pequeño documento fuente Latex que integra los dos comandos citados arriba.


\documentclass{article}
\usepackage[pdftex]{graphicx}
\begin{document}

Probando imágenes PNG en Latex
\includegraphics{images/foto0839.png}

\end{document}

Para finalizar, comparto un uso muy habitual de imágenes en documentos para hacer que se visualicen varias imágenes en un misma figura. Estas subimágenes son indexadas por letras (a), (b), (c), etc. Muy útil cuando queremos hacer comparaciones entre imágenes. Hay que utilizar el paquete subfigure y luego el comando subfigure que toma como argumento a includegraphics. Dejo un ejemplo de un fuente que utiliza el paquete subfigure.


\documentclass{article}
\usepackage[pdftex]{graphicx}
\usepackage{subfigure}
\begin{document}
Ejemplo de subfiguras
\begin{figure}[h]
  \centering
\subfigure[Donald Knuth]{\includegraphics{/home/admin/Escritorio/knuth.png}}
\subfigure[Richard Stallman]{\includegraphics{/home/admin/Escritorio/stallman.png}}
  \caption{Algunas figuras relevantes.}
\end{figure}
\end{document}

Al compilarlo con PDFLatex genera un PDF que presenta una hoja como la siguiente.

PDF que resulta de compilar el código fuente que utiliza el paquete subfigure

Dejo un par de links interesantes sobre el tema:

Historias de la Argentina

July 17th, 2008

Luego de la media sanción obtenida en Diputados, el proyecto del gobierno fue puesto en discusión ayer y hoy en el Senado. No soy especialista en política ni nada parecido, sólo quiero dar mi visión de lo sucedido.

Antes, quiero dejar en claro que no soy simpatizante ni del oficialismo, ni de la oposición. Tampoco estoy a favor del campo o en contra de las retenciones, en cambio estoy a favor de una Argentina mejor para TODOS.

Hoy el clima que se vive en el país no es muy alentador, ni tampoco agradable. Toda la Argentina se encuentra dividida por un problema (las retenciones al sector del campo), que a mi entender sólo a ocasionado que se vislumbre esta separación que ha existido desde hace mucho tiempo.

Durante muchas horas los senadores dieron sus argumentos en “favor” o en “contra” del proyecto. Una vez terminado el debate y llegada la hora del voto, se obtuvo un empate. La Constitución Nacional da el poder al presidente de la Cámara de Senadores, Julio Cobos, a votar para desempatar. Como he comentado en éste post anterior (que quede claro que tampoco soy simpatizante de él) y mi opinión, era que Cobos sólo era un político mas.

El político, como un empresario, busca (dentro de otras cosas) su beneficio propio. En este caso es obtener una buena imagen, para posteriormente obtener mayor cantidad de votos. No estoy en contra de este beneficio que persiguen, sólo estoy en contra de la ética que suelen utilizar para alcanzarlo.

Por ejemplo, un gobernado toma decisiones a nivel provincial que pueden afectar a varias personas. Pensemos en una persona que está cerca de la línea de indigencia. Una de estas decisiones puede ocasionar que se vuelva indigente. Esto trae aparejados varios problemas a nivel personal, como trastornos físicos (alimento, vestido, etc) o psíquicos (desempleo, ignorancia, etc) incluso producirle la muerte. Cuando sucede lo anterior, me pregunto ¿qué diferencia hay entre un político y un asesino? Es una pregunta difícil y fácil, según el contexto que utilicemos para responderla. Pero que no queda duda que las vidas de varias personas están en juego en las decisiones de uno (o varios) políticos. Esto me hace pensar en el compromiso que trae votar, ya que indirectamente somos parte de ésto…

Todo lo anterior se desprendió a lo que sucedió en el Senado. Hubieron algunos que defendieron sus intereses o los intereses de la “mayoría”. Dentro de este ámbito donde la mayor parte de los Senadores aprovechó esto como un trampolín para las próximas elecciones, quedó eclipsado por las palabras de Julio Cobos.

Aquí dejo un fragmento obtenido de crítica digital[criticadigital.com].

“Yo tengo que acompañar la institucionalidad. Mi corazón dice otra cosa y no creo que esto sea el motivo para poner en riesgo el país. Quiero seguir siendo el vicepresidente de todos los argentinos. (…) Yo creo que la presidenta de los argentinos me va a entender. No creo que nos sirva una ley que no soluciona este conflicto. La historia me juzgará no sé cómo. (…) No puedo acompañar. Y esto no significa que estoy traicionando a nadie. Estoy actuando en forma a mis convicciones. Yo le digo a la presidenta de los argentinos que tiene la oportunidad de enviar un nuevo proyecto que contemple todo lo que se ha dicho, todos los aportes que se han brindado. Que la historia me juzgue. Pido perdón si me equivoco. Mi voto no es positivo. Mi vito es en rechazo”

Los subrayados fueron mios, de ellos a mi parecer se puede ver la imagen de un hombre y no la careta de un político. Un hombre que quiere una mejor Argentina y no sólo para él o sus conocidos, sino para cada persona. Una Argentina no derrumbada por los beneficios o las idiosincrasias de la mayoría. Una Argentina unida. Él no estuvo a favor/contra del oficialismo/oposición. Estuvo a favor de sus convicciones, estas convicciones que pueden llevar a uno a ser una gran persona o ser un despreciable. Y la peor traición que pudo haber hecho es traicionar sus convicciones.

No soy optimista en cuanto al futuro de la Argentina, pero la actitud de éste hombre, que buscó el consenso de todos (él fue quien propuso llevar el debate al Congreso y además pidió un cuarto intermedio) da expectativas de un mañana mejor en este atormentado país.

Enlaces simbólicos y scp

July 9th, 2008

Me tocó hacer unos respaldos de cantidades importantes de archivos, entre dos equipos que se encontraban localizados en la misma red. Al enfrentar dicho trabajo, supuse erróneamente que sería muy fácil utilizando el comando scp, utilizando el parámetro r.


# scp -r /home/dante root@192.168.1.1:/mnt/disk015/dante

Se necesitaban respaldar aproximadamente 210GB. Calculé que el proceso iba a tomar aproximadamente unas 5 horas, dejo los cálculos, espero que estén bien :-P

  • 210 GB = 225485783040 Bytes
  • 225485783040 Bytes = 1803886264320 bits
  • 1803886264320 bits = 1803886 mbits
  • A 100 mbps -> 18038 segundos
  • 18038 segundos = 5 horas

La cuestión es que al pasar las cinco horas seguía copiando. Deje que siguiera, creyendo que había algún error de redondeo u horrores en los cálculos anteriores, pero luego de 3 horas más (con un total de 8 horas) ¡todavía seguía copiando!

Tenía dos hipótesis:

  1. Tengo serios problemas con las matemáticas.
  2. Pasa algo raro con el comando scp.

Con respecto a la primera todavía tengo dudas :-D En cuanto a la segunda, pude comprobar que scp no entiende los links simbólicos. Por lo tanto, al encontrar un link simbólico, no lo respeta y lo sigue, copiando todo el contenido al que apunta. Para entender la magnitud de esto, les sigo comentando mi experiencia.

rsync

Es un programa similar a rcp, pero tiene muchas más opciones. Además permite transferir sólo las diferencias entre archivos, logrando velocidad de transferencia.

Al revisar las copias, comprobé lo comentado anteriormente. Efectivamente, hacía copias de los contenidos apuntados por los links simbólicos. El problema principal fue un serie de links simbólicos que apuntaban a una carpeta llamada “Videos”,que pesaba unos 120GB y existían 3 links simbólicos a esta carpeta, entonces de los 120GB que creí que se debían copiar, pase a copiar ¡360GB!

Todo esto pude haberlo aludido si hubiese sabido sobre el comando rsync, su uso es tan sencillo como scp.


# rsync -r -l -t -v -u /home/dante root@192.168.1.1:/mnt/disk015/dante

Las opciones que utilicé indican.

r
Recursive, recurre dentro de los directorios.
l
Links, al encontrarse con un link simbólico lo copia como tal.
t
Time, preserva los tiempos (de los archivos) al copiarlos.
v
Verbosity, incrementa la verbosidad en la salida del comando.
u
Updates, no copia archivos que estén actualizados en el receptor.

Además de estas opciones, se encuentran muchas más y muy útiles. Puedes consultar todas las opciones y ejemplos de uso en las páginas man de rsync[samba.org].

Excluyendo carpetas o archivos

Al realizar un backup de una carpeta como home es frecuente que se encuentren archivos o carpetas que no necesitan ser respaldadas, esto puede ser indicado a rsync con el parámetro exclude. Por ejemplo, supongamos que queramos excluir del respaldo la carpeta foo/ relativa /home/dante/:


# rsync -r -l -t -v -u --exclude 'foo' /home/dante root@192.168.1.1:/mnt/disk015/dante

Nota: el archivo o carpeta a excluir debe ir entre comillas simples.

Excluir más de un archivo o carpeta

Será necesario editar un simple archivo de texto plano que liste los archivos o carpetas que no se deberán respaldar. Un pequeño ejemplo podría ser:


quux
quuux/tmp/*/*.pid
quuuux
baz

Guardamos el archivo como no_respaldar en /home/dante/ y se lo indicamos a rsync:


# rsync -r -l -t -v -u --exclude-from 'no_respaldar' /home/dante root@192.168.1.1:/mnt/disk015/dante

Problemas frecuentes

Al ejecutar el comando puede ser que obtengas la siguiente salida:


rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: remote command not found (code 127) at io.c(454) [sender=2.6.9]

Para solucionarlo basta instalar rsync también en la máquina remota.