Linux: Limitación de Descarga y Subida a nivel de Kernel

Teoría:

Cuando alcanzamos los límites de nuestra conexión, ya sea en subida y/o en bajada, los tiempos de respuesta (latencia, ping) se disparan, debido a que se están formando colas en el router. Y en general, los routers domésticos, gestionan muy mal las colas (son sistemas embebidos con muy poca memoria).

Por ello, es mejor acumular las colas en nuestros potentes ordenadores, en lugar de nuestros tristes routers que regalan con las portabilidades.

Realmente, lo de acumular la cola en el host, solo sirve para la subida, ya que la subida solo depende de nosotros. La técnica para controlar el límite de bajada es el siguiente: nuestro ordenador recibe paquetes, y tiene capacidad para gestionar todo el flujo pero intencionadamente se descartan paquetes hasta conseguir el flujo deseado. El punto anterior en la traza hasta nosotros, se dará cuenta que estamos descartando paquetes. Todos los routers interpretan esto como congestión, aunque sea congestión simulada. El router emisor se relaja hasta que le aceptemos todos los paquetes, que será cuando alcanzemos el flujo de descarga deseado. El único problema, es que cíclicamente los emisores probarán suerte volviendo aumentar el flujo para ver si hemos superado la congestión, y necesariamente cíclicamente se descartarán paquetes. Esto no es grave, también pasa cuando descargamos algo, y llega al auténtico límite de nuestra conexión, pero es interesante comentarlo.

Todo esto de controlar la congestión mediante colas en el propio host para mantener las latencias se denomina QoS. Calidad de servicio.

Aunque algunos routers caseros han intentado implimentar el QoS, en si experiencia, dejan bastante que desear. Si queremos un QoS de calidad, la única opción es montar un host sobre Linux que hará la función de router, entre otras cosas gestionando todos los flujos con QoS y prácticamente capacidad para colas tan grandes como nuestra capacidad RAM.

Si nuestra LAN es pequeña, este esquema no es barato, tener que tener un pc 24 horas con la función principal de rutear (pero router de calidad empresarial eso sí.). Otra forma sería poner los límites en cada uno de los hosts.

Evidenetemente las restricciones las pondrá un root, para que no haya forma de saltarse los límites de descarga/subida. Esto en Linux en fácil, en Windows, por su mal diseño, te obliga a trabajar como administrador, y por tanto podrías cerrar procesos como NetLimiter que realizan tambien QoS, pero en Windows.

Linux utiliza el comando “tc” para controlar los flujos, pero su uso es realmente extenso, por ello existe un script cuya funcionalidad se limita a un caso de uso muy común (limitar todo el ancho de banda, bajada y subida sin diferenciar Web de Emule, etc …). El script en cuestión es wondershaper.

Bueno, pasamos a lo interesante xD.

Práctica:

Hacemos un test de velocidad, asegurate que nadie use internet, o desenchufa a todos en el switch xD. Necesitamos los datos de la conexión en Kbps (bits). Es decir para 6 Mb de bajada 1 Mb de subida son 6144Kbps / 1024Kbps teorícos pero por el over heat del TCP/IP será un 15-20% menos, supongamos 5100/750. Ese es el limite real, que sera lo que deevuelva un test de velocidad. A ese resultado reducirlo otra 20% más, como margen para permitir una ventana de concurrencia con los demás hosts, quedandose 4080 Kbps / 600 Kbps. Hemos puesto un colchon de un 20%, debeis probar varios valores, entre mayor sea el colchón más asegurado esta el ping. con un 20% debería no subir nunca el ping, pero si de por sí vuestro router es malo(puede repartir mal el tiempo entre bocas), por puede que necesiteis más colchón para asegurar la calidad del servicio. Ahora simplemente INSTALAR Y LIMITAR.

Instalamos el script: sudo apt-get install wondershaper
Con ifconfig miramos nuestro interfaz en uso: Por ejemplo, en mi caso eth0.
Limitramos la conexión: sudo wondershaper eth0 4080 600
Yo aparte me he puesto un alias en el .bash_aliases: alias limitar=’sudo wondershaper eth0′

Ahora hay que hacer pruebas, limitar todos los hosts, aumentar la concurrencia y en todo host debería tener unos tiempos mínimos de latencia. Si realmente necesitas un colchón muy grande, como un 60% o así, es que tienes un problema en tu red, probablemente exceso de colisiones, puede que uses un hub, o que la red sea muy grande y necesites separar los dominios de colisión con routers o puentes.

El script depende de iproute, en otras distribuciones tambien llamado iproute2, en ubuntu viene instalado, pero igual en otras distribuciones no viene.

Cuando ya tengais los valores correctos, para hacerlo definitivos:

1º Editamos: sudo gedit /etc/network/interfaces
2º Y lo dejáis así, pero con vuestros valores :D:

auto lo
iface lo inet loopback
up /usr/sbin/wondershaper eth0 4080 600
down /usr/sbin/wondershaper remove eth0

Existen otras formas, más dinámicas y válidas para cualquier adaptador con los script de if.up e if.down pero a mi me vale así.

Por último para eliminar el QoS (y se puede deducir del paste anterior) escribimos:
sudo wondershaper remove eth0

Ya puedo jugar el Counter Strike, mientras los demás están con el JDownloader, Emule, Torrent … !! :D

Pasar secuencia de imagenes a video

En concreto lo estoy utilizando para las animaciones generadas por blender en archivos png:

ffmpeg -y -f image2 -i %4d.png -b 10800k render.avi && gnome-open render.avi

Script para hacer screenshots durante “M” minutos cada “T” segundos

He hecho un script que me ha sido muy útil para monitorear una ventana que no logea por ningun lado.


m=1; T=5; for i in $(seq $[($m*60)/$T]); do import -window root -quality 80 `date +"%d-%m-%Y_%H:%M:%S"`.jpg; sleep $[$T-1]; done;

El script es 1 linea con 2 constantes a variar según las necesidades:
m: Es el número de minutos que va a estar haciendo screenshots
T: Es la frecuencia de screen en segundos.

En el ejemplo durante 1 minuto hace screen cada 5 segundos, por tanto hará 12 screenshots de unos 100KB cada una.

Nota: si no veis bien la linea(se puede copiar entera, pero mi blog la corta), la he subido a pastebin
Nota2: el script no es preciso en el tiempo. Por cada minuto que pongais se puede ir unos segundos arriba o abajo. El error viene de presuponer que se tarda 1 segundo en hacer un screenshot.

Script para ripear imagenes masivamente* (Actualizado)

Ultima modificación: jueves, 28 de mayo de 2009

Necesitaba ripear unas 5000 imagenes en el curro, en cada una de ellos necesitaba pasarlo de TIFF a JPG y fijar el ancho a 800 y alto libre manteniendo aspect ratio.

Me he hecho este script cuyo uso simplemente es pasar todos las carpetas que vamos a trabajar como parametros. Por ejemplo:

Uso: ripearImagenes CARPETA1 CARPETA2 CARPETA3 … CARPETAN

Escribiendo ripearImagenes sin parametros es equivalente a pasar el directorio actual como primer parametro.

Simplemente gedit ripearImagenes y pasteamos, además podeis poneros el script en algún directorio “PATHeado” (evidentemente, esto ultimo es opcional xD):

#!/usr/bin/python

#
# :: Invasion Tux
# :: Ultima modificacion : jueves, 28 de mayo de 2009
# :: Script realizado por makiolo (makiolo@gmail.com) (Licencia Creative Commons con reconocimiento)
# :: Ultima version : https://blogricardo.wordpress.com/2009/05/15/script-para-ripear-imagenes-masivamente/
# :: Dependencias : python , convert
#

import os,sys,glob,subprocess,shutil

######### CONFIGURACION ##############

SUFIJO = "_RIPEADO"
DESTINO = ".png"
ANCHO = 2000
FORMATOS_VALIDOS = ["jpg","gif","png","tif"]

######################################

def getExtension(fichero):
	posPunto = video.rfind(".")
	return fichero[posPunto+1:len(fichero)]

def extensionEsValida(fichero):
	posPunto = video.rfind(".")
	if posPunto != -1:
		extension = getExtension(fichero)
		try:
			FORMATOS_VALIDOS.index(extension)
			return True
		except ValueError:
			return False
	else:
		return False

def getNombreRipeado(fichero):
	return fichero+SUFIJO+DESTINO

def getCarpetaRipeados( dir_inicial ):
	return "%s_RIPEADOS" % ( os.path.basename(dir_inicial) )

def existeRipeado(fichero):
	return os.path.exists(getNombreRipeado(fichero))

def ripear(fichero):
	ret = subprocess.call('convert "%s" -quiet -resize %d "%s"' % ( fichero , ANCHO , getNombreRipeado(fichero) ) , shell=True)
	return ret == 0

def ripearTodo( carpeta ):
	imagenes = []
	for extension in FORMATOS_VALIDOS:
		imagenes += glob.glob("*."+extension)
	borradas = 0
	copia = []
	lenFinal = len(SUFIJO+DESTINO)
	for imagen in imagenes:
		if(imagen[-lenFinal:] != SUFIJO+DESTINO):
			if os.path.isfile(imagen):
				copia.append(imagen)
		else:
			os.remove( imagen )
			borradas = borradas + 1
	print "+ Borradas %d imagenes ripeadas" % (borradas)

	total = len(copia)
	print "+ Ripeando %d imagenes: " % total
	i = 1
	for imagen in copia:
		print "  - Ripeando %d de %d\r" % (i , total),
		sys.stdout.flush()
		if ripear(imagen):
			shutil.move( getNombreRipeado(imagen) , carpeta)
		else:
			print "Error ripeando %s. Posiblemente no sea una imagen." % (imagen)
		i+=1

def App():
	try:
		if len(sys.argv) == 1:
			sys.argv.append(".")
		dir_inicial = os.getcwd()
		for parm in sys.argv:
			if parm != sys.argv[0]:
				if (os.path.isdir(parm)):
					carpeta = getCarpetaRipeados( dir_inicial )
					if not os.path.exists(carpeta):
						os.mkdir(carpeta)

					parm = os.path.abspath( parm )
					carpeta = os.path.abspath( carpeta )
					os.chdir(parm)
					print "Trabajando %s" % parm
					ripearTodo( carpeta )
					os.chdir( dir_inicial )
				else:
					print '"%s" no es un directorio' % parm
	except KeyboardInterrupt:
		print "ancelado por el usuario"

if __name__ == '__main__':
	App()

Espacio en disco ocupado por un directorio

Un comando muy útil es du. Sirve para calcular el espacio que ocupa un disco un diretorio. Para ello calcula todo lo que tiene dentro del directorio, (recursivamente para el caso de los directorios). El uso simple es pasando el directorio como primer y único parámetro. Por ejemplo:

makiolo@blog:~$ du /home/makiolo/videos/The\ Big\ bang\ Theory/temp2
3048960    /home/makiolo/videos/The Big bang Theory/temp2

Para poner las unidades comprensibles añadimos el parametro -h:

makiolo@blog:~$ du -h /home/makiolo/videos/The\ Big\ bang\ Theory/temp2
3,0G    /home/makiolo/videos/The Big bang Theory/temp2

Mostrando solo los GB libres:

makiolo@blog:~$ du -h /home/makiolo/videos/The\ Big\ bang\ Theory/temp2 | tail -n1 | cut -f1
3,0G

Jugando más con las tuberías:

makiolo@blog:~$ du -h /home/makiolo/videos/The\ Big\ bang\ Theory/temp2 | tail -n1 | awk ‘{print “El directorio “$2” ocupa “$1}’
El directorio /home/makiolo/videos/The Big bang Theory/temp2 ocupa 3,0G

Me hago un script final que es el que usaré, gedit espacioLibre.sh y pasteamos:

#!/bin/sh

if [ $# = 0 ]; then
DIRECTORIO=`pwd`
else
DIRECTORIO=$1
fi;

du -h $DIRECTORIO | tail -n 1 | awk ‘{print “El directorio ” $2 ” ocupa ” $1}’

Script para hacer copias de seguridad incrementales

Actualizado : lunes, 09 de febrero de 2009
Hoy público en script que tenía hace tiempo funcionando pero muy mal estructurado, hoy he estado puliendolo y creo que esta suficientemente presentable como para publicarlo. Esta basado en bash (no es necesario python para nada) y la idea es poder hacer copias incrementales de la forma más fácil posible. (sin parametros o pocos parametros con buenos valores por defecto).

El script se puede ejecutar con 0, 1 o 2 parametros:

  • 0 parametros : si simplemente ejecutamos el script, sin parametros, considerará que quieres hacer una copia de seguridad del directorio de trabajo actual. Si el directorio activo es por ejemplo: /home/makiolo/descargas se creara el directorio copia_de_descargas con la copia principal y las copias incrementales.
  • 1 parametros : si no queremos especificar el directorio que queremos salvar de forma implicita (por directorio de trabajo), sencillamente pasamos la ruta del directorio que queremos salvar(absoluta o relativa) como primer parametro. Se creara en el mismo directorio que queremos salvar la carpeta copia_de_$nombre con la copia principal y las copias incrementales. Como he dicho las rutas pueden ser relativas o absolutas, pero es recomendable las absolutas pero definitivamente evitar el determinismo del directorio de trabajo.
  • 2 parametros : Tener la copia de seguridad junto original no es muy útil si sufrimos una perdida de información. Es evidentemente recomendable tener la copia en un disco distinto al original. Por tanto:
    • 1er parametro : carpeta que queremos salvar.
    • 2º parametro : destino de la copia de seguridad
  • Alguna cosas más importantes:
    • .rsyncExcluir : se hace un listado de directorios y archivos que se excluyen de la copia de seguridad. Si no existe se crea excluyendo a si mismo y al destino de la copia de seguridad. Para evitar hacer una copia de la copia :/
    • En copia_de_$nombre/principal/ : Esta es la copia más reciente, y si ejecutas tu comando con cierta frecuencia es una copia exacta del original.
    • En copia_de_$nombre/incrementales/ : Se crea un incremental por día, (excepto si en ese día no hubo cambios). Tal y como esto en AÑO-MES-DIA, no sería dificil cambiar el date para realizar otro tipo de partición. Si especificamos hora y minuto podría ser excesivamente particionado. Podríamos cambiar el script para agrupar por otros criterios, por ejemplo fecha+turno (grupo de mañana o de tarde), o por numero de la semana si las copias de seguridad son semanales. En los incrementos solo se guarda el cambio respecto al principal que se hizo ese día.
  • Asi que simplemente hacer gedit copiaSeguridad , copy & paste  y darle permisos.
#!/bin/sh
#
# :: Invasion Tux
# :: Ultima modificacion : lunes, 09 de febrero de 2009
# :: Script realizado por makiolo (makiolo@gmail.com)  (Licencia Creative Commons con reconocimiento)
# :: Ultima version : https://blogricardo.wordpress.com/2009/02/08/script-para-hacer-copias-de-seguridad-incrementales
# :: Dependencias : rsync
#

################################# VARIABLES ##############################################

if [ $# -eq 0 ]; then
	# Directorio que queremos salvar
	DIRECTORIO_A_SALVAR=`pwd`

	# construir nombre subdirectorio
	NOMBRE_MES_ANIO=`date +"el_mes_%m_del_%Y"`
	NOMBRE_SALVADO=`basename $DIRECTORIO_A_SALVAR`
	SUB_DIRECTORIO_A_SALVAR="copia_de_"$NOMBRE_SALVADO"_en_"$NOMBRE_MES_ANIO

	# directorio donde se guarda el backup
	DESTINO_DE_LA_COPIA=$DIRECTORIO_A_SALVAR/$SUB_DIRECTORIO_A_SALVAR
elif [ $# -eq 1 ]; then
	# Directorio que queremos salvar
	DIRECTORIO_A_SALVAR=$1

	# construir nombre subdirectorio
	NOMBRE_MES_ANIO=`date +"el_mes_%m_del_%Y"`
	NOMBRE_SALVADO=`basename $DIRECTORIO_A_SALVAR`
	SUB_DIRECTORIO_A_SALVAR="copia_de_"$NOMBRE_SALVADO"_en_"$NOMBRE_MES_ANIO

	# directorio donde se guarda el backup
	DESTINO_DE_LA_COPIA=$DIRECTORIO_A_SALVAR/$SUB_DIRECTORIO_A_SALVAR
elif [ $# -eq 2 ]; then
	# Directorio que queremos salvar
	DIRECTORIO_A_SALVAR=$1

	# construir nombre subdirectorio
	NOMBRE_MES_ANIO=`date +"el_mes_%m_del_%Y"`
	NOMBRE_SALVADO=`basename $DIRECTORIO_A_SALVAR`
	SUB_DIRECTORIO_A_SALVAR="copia_de_"$NOMBRE_SALVADO"_en_"$NOMBRE_MES_ANIO

	# directorio donde se guarda el backup
	DESTINO_DE_LA_COPIA=$2/$SUB_DIRECTORIO_A_SALVAR
else
	echo "Numero de parametros incorrecto"
	exit
fi

# Archivos donde listamos las exlusiones de la backup
FICHERO_DE_EXCLUSION=$DIRECTORIO_A_SALVAR/.rsyncExcluir

# subdirectorio donde se guarda la copia principal
COPIA_PRINCIPAL=$DESTINO_DE_LA_COPIA/principal

# subdirectorios donde se guardan las copias incrementales
COPIA_INCREMENTOS=$DESTINO_DE_LA_COPIA/incrementales

# ruta variable de copias incrementales
COPIA_INCREMENTOS_VARIABLE=$COPIA_INCREMENTOS/`date | awk '{print $3}'`

# opciones de rsync , mejor no tocar
OPCIONES="--force --ignore-errors --delete --delete-excluded \
 --exclude-from=$FICHERO_DE_EXCLUSION --backup --backup-dir=$COPIA_INCREMENTOS_VARIABLE -av"

################################# FUNCIONES ##############################################
ejecutarRsync()
{
	if [ ! -f $FICHERO_DE_EXCLUSION ]; then
		echo `basename $DESTINO_DE_LA_COPIA`"/" > $FICHERO_DE_EXCLUSION
		echo ".rsyncExcluir" >> $FICHERO_DE_EXCLUSION
		echo "*~" >> $FICHERO_DE_EXCLUSION
	fi
	rsync $OPCIONES $DIRECTORIO_A_SALVAR $COPIA_PRINCIPAL
}

################################# MAIN ##############################################

# nos aseguramos de que existen los directorio de destino de la copia de seguridad
mkdir -p $DESTINO_DE_LA_COPIA
mkdir -p $COPIA_PRINCIPAL
mkdir -p $COPIA_INCREMENTOS

if [ ! -d $DIRECTORIO_A_SALVAR ]; then
	echo "No se encontro el directorio a salvar : $DIRECTORIO_A_SALVAR";
elif [ ! -d $DESTINO_DE_LA_COPIA ]; then
	echo "No se encontro el directorio de destino de la copia : $DESTINO_DE_LA_COPIA";
else
	ejecutarRsync
fi

Es un script excelente para combinarlo con un cron 24h.

Si no entendeis para que sirve el script o no sabeis que es una copia incremental –> google xD, no hombre podeis preguntarmelo y eso xD

Tambien si encontrais algún bug os lo agradeceré mucho que lo comenteis.

Script para generar diccionarios de fuerza bruta

Ultima modificación : miércoles, 10 de diciembre de 2009

Necesitaba abrir un pdf protegido por contraseña. Era un pdf con las notas de mi novia, y el cual el profesor se iba equivocado metiendo la contraseña y la pobre se iba a quedar todas las navidades sin saber la nota, asi que intentamos hacer fuerza bruta sobre el fichero, con exito.

Desarrolle un script en python que generara palabras de una longitud máxima a partir de un cadena que define un alfabeto. En mi ejemplo configuro las variables con estos valores:

LONGITUD = 6
ALFABETO = "abcdefghijklmnopqrstuvwxyz0123456789_-."

Generar todas las combinaciones posibles conlleva no solo considerar las de longitud 6, si no tambien las de longitud 5,4,3,2 e incluso 1. El alfabeto tiene 39 caracteres por tanto todas las combinaciones posibles son:

calculo de combinaciones

cálculo de combinaciones

Contraseñas de longitud mayor que 8 son muy costosas computacionalmente, por ello el script que he realizado me interesa que de mucha información de cuanto queda y cuanto lleva. En concreto 3 cosas:

  • El porcentaje que lleva del total.
  • Tiempo estimado restante (en horas, lo he puesto).
  • Velocidad: en palabras generadas por segundo

Con el dual core de mi portatil a 2.2 Ghz y con el ejemplo que pongo de palabras de hasta 6 caracteres y un alfabeto de 39 caracteres, los tiempos son muy buenos (aunque queda pendiente el uso de paralelización por MPI o algo así):

  • Velocidad media aprox: 610.000 palabras generadas / seg
  • Tiempo total : 1 hora 50 min

A continuación os pasteo el script (abrir un gedit generarDiccionario ):

Sigue leyendo