commit c011257ad4fd9a32205986f19866f481a4eeb4fd
parent ff9ebcf5f5c00eccad34318c1ef6f9ec1a670dca
Author: fjbalon <fjbalon@templier.es>
Date: Mon, 5 Oct 2026 00:34:20 +0200
Añadidos artículos generales de temas computacionales
Diffstat:
39 files changed, 1912 insertions(+), 1 deletion(-)
diff --git a/dwm/index.html b/dwm/index.html
@@ -36,7 +36,7 @@
<li>Se inicia instantáneamente, incluso en máquinas de baja potencia.</li>
<li>Es independiente. Puede ser compilado y ejecutado en cualquier heredero de Unix, sea GNU/Linux, sea BSD, sea Solaris.</li>
<li>Implementa un reflejo, efigie perfecta de mis propios patrones de uso:</li>
-<ol>
+<ol type="a">
<li>No quiero redimensionar o mover una ventana manualmente de primeras, a no ser que quiera hacerlo.</li>
<li>Normalmente tengo al menos dos ventanas abiertas, una al lado de la otra; una maestra y otra esclava.</li>
<li>A veces quiero mutar una ventana a pantalla completa rápidamente, y volver al estado anterior con la misma velocidad.</li>
diff --git a/git-server/index.html b/git-server/index.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Construcción de mi propio servidor Git</title>
+<link rel="icon" type="image/png" href="/favicon.png" />
+<link rel="stylesheet" type="text/css" href="../article.css" />
+</head>
+<body>
+<header>
+<p class="title">Construcción de mi propio servidor Git</p>
+<p class="date">22 de noviembre de 2020 • fjbalon</p>
+</header>
+<p>Aquí todos conocemos el software o protocolo desarrollado en inicio por Linus Torvalds: Git. Un sistema de control de versiones, que se constituye como una herramienta indispensable, a día de hoy, para cualquier programador; especialmente en el software libre. Git funciona como cliente o como servidor, y cada cliente aloja en local una copia del software que sincronizará con el servidor en función de lo que el cliente convenga. Los despliegues de Git más conocidos son Github o Gitlab, donde éstos te ofrecen una interfaz gráfica pulida y almacenamiento de servidor para todos los proyectos que se deseen incluir. Por ello, la duda razonable que debe asaltar al lector sería: ¿por qué querría crear mi propio servidor de Git?</p>
+<p>Veamos, una buena razón para alojar tus propios repositorios Git es tener y mantener el control sobre tu propia infraestructura informática, tanto a nivel de sistema como a nivel de código, guardando incluso el secreto de aquellos códigos que quieras mantener sin publicar (y que de otra forma lo estarías cediendo al ordenador de otro, confiando ciegamente en que verdaderamente se encuentre oculto). Considero que los servidores de Git comúnmente utilizados como Github, Gitlab, Bitbucket… No son de fiar, en cuanto son propietarios desconocidos y sostenedores de tu código. No es secreto que estos servicios analizan el código, aplican telemetría e inteligencia sobre ellos, analizan las conexiones de sus usuarios y aplican restricciones y limitaciones. Al fin y al cabo son empresas con fines comerciales, y a menudo con fines ocultos. En el caso de Microsoft, como propietario de Github es mucho más lamentable y peligrosa la situación.</p>
+<p>En cuanto a economía doméstica, estos servicios también tienen diferentes planes de precios y varias restricciones (arbitrarias en muchos casos). Sin embargo cuando usted mismo lo aloja, las restricciones son los límites de recursos del sistema y su conexión, por lo tanto, es una solución mucho más flexible, adaptada y convergente con el usuario.</p>
+<h2>¿Cómo creo mi propio servidor de Git?</h2>
+<p>Bien, entremos en el barro técnico.</p>
+<p>Lo primero que debemos hacer es tener Git instalado. Debido a la gran cantidad de distribuciones y formas variopintas de realizar la instalación, voy a obviarla. No es dificil instalar Git y se encuentra disponible, que yo sepa, en todos los repositorios oficiales de todas las distros.</p>
+<p>También voy a obviar el uso general de Git. No es objetivo de esta entrada explicar cómo realizar cambios en el software, realizar commits, status, push y pull, revisar el histórico de cambios, etcétera. Si me animo podría escribir un post a parte a modo de curso, del uso de Git a nivel de cliente. Pero en este caso me centro en el servidor.</p>
+<p>Para ello, el primer paso sería crear el usuario git (a nivel de sistema operativo), encargado de gestionar todos los procesos referentes a los repositorios y al servidor. Además, con el objetivo de dotar acceso mediante SSH añadimos authorized_keys y añadimos al fichero las claves públicas de los clientes.</p>
+<pre><code>adduser git
+su git
+cd
+mkdir .ssh && chmod 700 .ssh
+touch .ssh/authorized_keys
+chmod 600 .ssh/authorized_keys</code></pre>
+<p>Los repositorios pueden estar en el directorio que se quiera. En este caso, se encontrarán en el directorio git en la raíz del sistema. Para lo que tendremos que crearlo. Por cada repositorio, se crea un directorio (aconsejable es que terminen con .git). Para iniciar un repositorio como server usamos el parámetro <emb>init --bare.</emb></p>
+<pre><code>mkdir /git
+cd /git
+mkdir code.git
+chown git:git code.git
+cd code.git
+git init --bare
+Initialized empty Git repository in /git/code.git/</code></pre>
+<h2>Publicación de repositorios</h2>
+<p>Quien haya sido un poco sagaz, se habrá dado cuenta que de esta forma el único que puede acceder a dichos repositorios es aquel que conozca la contraseña del usuario git, o bien que su clave pública esté alojada en el servidor para que sea reconocido. Es decir, sólo podría acceder al repositorio el que conozca personalmente al propietario del servidor.</p>
+<p>Por ello tenemos la opción de publicar el repositorio, de forma que pueda ser clonado por todos (al igual que en Github y similares).</p>
+<p>Para ello empleamos <emb>git-daemon</emb>, indicándole el directorio donde se encuentran los repositorios.</p>
+<pre><code>git daemon --reuseaddr --base-path=/git/ /git/</code></pre>
+<p>Esto no basta para publicar el repositorio, ya que el demonio de git iterará en el directorio anteriormente pasado en busca de repositorios exportables, éstos son aquellos que tengan el fichero <emb>git-daemon-export-ok</emb> en su raíz.</p>
+<pre><code>touch /git/code.git/git-daemon-export-ok</code></pre>
+<p>De esta forma, cualquier cliente podría clonar el repositorio usando la siguiente dirección:</p>
+<pre><code>git clone git://templier.es/code.git</code></pre>
+<h2>En el lado del cliente</h2>
+<p>De esta simple forma, cualquier equipo que tenga acceso al servidor podría, a través de Git y SSH, clonar repositorios. En el lado del cliente, configuraríamos nuestros parámetros (globales, si no sabes lo que haces):</p>
+<pre><code>git config --global user.name "fjbalon"
+git config --global user.email fjbalon@templier.es
+git config --global core.editor vim</code></pre>
+<p>O directamente modificando el fichero <emb>~/.gitconfig</emb>:</p>
+<pre><code>[user]
+email = fjbalon@templier.es
+name = fjbalon
+[core]
+editor = vim</code></pre>
+<p>La descarga mediante SSH y mediante repositorio público se hará de tal forma:</p>
+<pre><code>git clone git@templier.es:/git/code.git
+git clone git://templier.es/code.git</code></pre>
+</body>
+</html>
+\ No newline at end of file
diff --git a/git-stagit/index.html b/git-stagit/index.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Externalización gráfica de servidor Git propio con stagit</title>
+<link rel="icon" type="image/png" href="/favicon.png" />
+<link rel="stylesheet" type="text/css" href="../article.css" />
+</head>
+<body>
+<header>
+<p class="title">Externalización gráfica de servidor Git propio con stagit</p>
+<p class="date">23 de noviembre de 2020 • fjbalon</p>
+</header>
+<p>A veces es agradable navegar por el registro del historial de git en un navegador web o en algún otro programa sin tener que mirar el repositorio local. Es además una forma de mantener un registro de los repositorios que sean públicos, a modo de currículum o expositor de código. Si además se cumple el requisito personal de cumplir con una regla o una filosofía minimalista, de web estática en este caso y libre, aún mejor.</p>
+<p>Para ello uso el impecable <a href="https://codemadness.org/git/stagit">stagit</a>, que es un generador de pagínas estáticas para git desarrollado por <a href="https://codemadness.org">codemadness.org</a>. Su uso es simple. Manualmente consta de dos partes, que son la creación de directorios html (que deben ser accesibles mediante servidor web) y su enlace con el directorio del servidor git:</p>
+<pre><code>mkdir -p /srv/git/htmlrepo1 && cd /srv/git/htmlrepo1
+stagit /git/gitrepo1</code></pre>
+<p>Y la formación del índice y el htmlroot:</p>
+<pre><code>cd /srv/git
+stagit-index /git/gitrepo1 /git/gitrepo2 /git/gitrepo3 > index.html</code></pre>
+<p>Ejemplos de resultados son <a href="https://templier.es/git/">templier.es/git</a>, <a href="https://codemadness.org/git/">codemadness.org/git</a> o <a href="https://git.suckless.org/">git.suckless.org</a>.</p>
+<h2>Automatización de actualización de repositorios</h2>
+<p>Para automatizar la actualización del directorio en función de los cambios de push añadimos a htmlroot (<emb>/srv/git</emb>) el script:</p>
+<pre><code># /srv/git/create.sh
+reposdir="/git"
+curdir="$(pwd)"
+
+stagit-index "${reposdir}/"*/ > "${curdir}/index.html"
+
+for dir in "${reposdir}/"*/; do
+ # strip .git suffix.
+ r=$(basename "${dir}")
+ d=$(basename "${dir}" ".git")
+ printf "%s... " "${d}"
+
+ mkdir -p "${curdir}/${d}"
+ cd "${curdir}/${d}" || continue
+ stagit -c ".cache" -u "/git/$d/" "${reposdir}/${r}"
+
+ # symlinks
+ ln -sf log.html index.html
+ ln -sf ../style.css style.css
+ ln -sf ../logo.png logo.png
+ ln -sf ../favicon.png favicon.png
+
+ echo "done"
+done</code></pre>
+<p>Por supuesto, el script anterior debe contar con permisos de ejecución; y el directorio htmlroot debe tener permisos adecuados para su manipulación, que siendo en este caso el usuario git el que genere de nuevo los HTML, debería éste tener permisos totales.</p>
+<p>Además, por cada repositorio del servidor debemos añadir el hook post-receive tal que:</p>
+<pre><code>#!/bin/sh
+# /git/code.git/hooks/post-receive
+
+export LC_CTYPE="en_US.UTF-8"
+
+name="$1"
+if test "${name}" = ""; then
+ name=$(basename "$(pwd)")
+fi
+
+reposdir="/git"
+dir="${reposdir}/${name}"
+htmldir="/srv/git"
+stagitdir="/"
+destdir="${htmldir}${stagitdir}"
+cachefile=".htmlcache"
+
+if ! test -d "${dir}"; then
+ echo "${dir} does not exist" >&2
+ exit 1
+fi
+cd "${dir}" || exit 1
+
+force=0
+while read -r old new ref; do
+ test "${old}" = "0000000000000000000000000000000000000000" && continue
+ test "${new}" = "0000000000000000000000000000000000000000" && continue
+
+ hasrevs=$(git rev-list "${old}" "^${new}" | sed 1q)
+ if test -n "${hasrevs}"; then
+ force=1
+ break
+ fi
+done
+
+r=$(basename "${name}")
+d=$(basename "${name}" ".git")
+printf "[%s] stagit HTML pages... " "${d}"
+
+mkdir -p "${destdir}/${d}"
+cd "${destdir}/${d}" || exit 1
+
+if test "${force}" = "1"; then
+ rm -f "${cachefile}"
+ rm -rf "commit"
+fi
+
+stagit-index "${reposdir}/"*/ > "${destdir}/index.html"
+stagit -c "${cachefile}" -u "/git/$d/" "${reposdir}/${r}"
+
+ln -sf log.html index.html
+ln -sf ../style.css style.css
+ln -sf ../logo.png logo.png
+
+echo "done"</code></pre>
+<p>También debe contar con privilegios de ejecución. Lo que hará que en cada push recibido, el contenido HTML de stagit se actualice.</p>
+<p>Para una correcta impresión de los datos, es necesario que cada directorio de repositorio tenga en su raíz los ficheros owner, description y url:</p>
+<pre><code>cd /git/code
+echo "fjbalon" > owner
+echo "Descripción del repositorio" > description
+echo "git://templier.es/code.git" > url</code></pre>
+<p>Las imágenes por defecto empleadas son favicon.png y logo.png, que irán en la raíz de htmlroot (/srv/git). También style.css.</p>
+<pre><code>cp stagit/style.css /srv/git/
+cp stagit/favicon.png /srv/git/
+cp stagit/logo.png /srv/git/</code></pre>
+<h2>Autodespliegue con hooks</h2>
+<p>En este ejemplo damos al hook post-receive del repositorio del sitio web la capacidad de autodesplegarse al recibir push, con el ejemplo de esta propia web estática para que, con mi propio push autenticado por SSH, automáticamente se lance como actualización al servidor Apache.</p>
+<pre><code>#!/bin/sh
+# /git/arrakis.git/hooks/post-receive
+
+echo "Ejecutando hook postreicive: desplegando a producción el static-site"
+git --work-tree=/srv/http --git-dir=/tex/arrakis.git checkout -f master</code></pre>
+<p>Por supuesto, los permisos del directorio htmlroot deben tener los permisos para git.</p>
+<pre><code>drwxr-xr-x 3 git git 4096 Dec 14 15:53 http</code></pre>
+</body>
+</html>
+\ No newline at end of file
diff --git a/http-darkmode/RGB.png b/http-darkmode/RGB.png
Binary files differ.
diff --git a/http-darkmode/index.html b/http-darkmode/index.html
@@ -0,0 +1,338 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Algoritmo para determinar el grado del modo oscuro en imágenes invertidas</title>
+<link rel="icon" type="image/png" href="/favicon.png" />
+<link rel="stylesheet" type="text/css" href="../article.css" />
+</head>
+<body>
+<header>
+<p class="title">Algoritmo para determinar el grado del modo oscuro en imágenes invertidas</p>
+<p class="date">11 de junio de 2024 • fjbalon</p>
+</header>
+
+<p>No son pocas las ocasiones en que los sitios web ofrecen, a través de código javascript y cookies, sistemas de switch (o conmutador, en cristiano) del sistema claro u oscuro. Por la salud visual de los lectores, creo importante mantener este elemento fácil. En mi experiencia personal, creo que con un modo claro (en base a blanco) y un moco oscuro (base a negro puro) es más que suficiente. Además, el segundo se supone que aporta un mejor rendimiento en pantallas amoled, y visualmente un negro puro queda mucho más estético, a pesar de la tentación de mantener unos tonos grisáceos que, según otros, mejoran enormemente la lectura; pero ni tengo el conocimiento para defenderlo ni el necesario para atacarlo. El negro puro se constituye como un elemento, en mi uso personal, básico: utilizo un gestor de ventanas en mosaico con fondo negro, el fondo de la terminal st en negro, etc. Quiero entonces que, en cohesión con mi ecosistema, el fondo sea negro. Simple.</p>
+<p>¿Cómo lograrlo en un sitio web estático? Simple, CSS trae la solución en sí mismo: la función de medios CSS <emb>prefers-color-scheme</emb> se utiliza para detectar si un usuario ha solicitado temas de colores claros u oscuros, siendo que indica su preferencia a través de una configuración del sistema operativo o una configuración del agente de usuario que indica el propio navegador. De tal forma que podemos configurar las preferencias para el modo claro o light y oscuro o dark. Tampoco es estrictamente necesario establecer ambos, simplemente con dejar uno, el otro se establecería como defecto negativo.</p>
+<pre><code>@media (prefers-color-scheme: light) {
+ body {
+ color: black;
+ background-color: white;
+ }
+}
+
+@media (prefers-color-scheme: dark) {
+ body {
+ color: white;
+ background-color: black;
+ }
+}</code></pre>
+<p>Pero el problema de todo modo switch de modo oscuro son las imágenes. No hablamos de imágenes vectoriales como SVG, que tienen ya el propio soporte en CSS, sino imágenes de mapas de bits que, a menudo, no tienen siempre transparencia y el fondo blanco contrasta con el fondo negro, dejando un aspecto muy poco estético. Yo, que debo ser muy quisquilloso, no puedo consentirlo.</p>
+<p>Se me ocurren un par de formas de solucionar esto:</p>
+<ol>
+<li>Utilizando un switch con dos imágenes, una para modo claro y otra para modo oscuro. Indicando un CSS:
+<pre><code>.only-on-dark {
+ display: none;
+}
+
+@media (prefers-color-scheme: dark) {
+ .only-on-dark {
+ display: block;
+ }
+
+ .only-on-light {
+ display: none;
+ }
+}</code></pre>
+<p>De tal forma que se indique en el HTML ambas imágenes con la clase a la que se deben:</p>
+<pre><code><img class="only-on-dark" src="dark-image.png" />
+<img class="only-on-light" src="image.png" /></code></pre>
+<p>Quizá sea preferible también embeberlo directamente en el HTML, de tal forma que:</p>
+<pre><code><picture>
+ <!-- Usuario prefiere modo claro -->
+ <source srcset="image.png" media="(prefers-color-scheme: light)"/>
+
+ <!-- Usuario prefiere modo oscuro -->
+ <source srcset="dark-image.png" media="(prefers-color-scheme: dark)"/>
+
+ <!-- Usuario no indica preferencia -->
+ <img src="image.png"/>
+</picture></code></pre>
+<p>De esta forma evitaríamos la descarga de la variante oculta.</p>
+</li>
+<li>
+<p>Una seguna solución, más eficiente en cuanto a que no necesitaríamos dos versiones de la imagen, sería invertir a través de CSS el color de la imagen original (siempre en el caso de que la inversión no suponga la subversión de la imagen, claro está) en caso de encontrarnos en modo oscuro.</p>
+<p>De tal forma que mantendríamos una clase, sea por ejemplo <emb>color-invertible</emb>, que identificaría a la imagen:</p>
+<pre><code><img class="color-invertible" src="image.png"/></code></pre>
+<p>Para que en el CSS le indicásemos, dentro de <emb>prefers-color-scheme: dark</emb>:</p>
+<pre><code>@media (prefers-color-scheme: dark) {
+ .color-invertible {
+ filter: invert(100%);
+ }
+}</code></pre>
+</li>
+</ol>
+<p>Pero, ¿y si no estoy usando como creo más conveniente un fondo totalmente negro? ¿y si el fondo que estoy usando es, por ejemplo, (28, 28, 28)?... Creo conveniente realizar antes un breve repaso al funcionamiento técnico del color RGB:</p>
+<p>RGB es, entonces, un modelo de color basado en la síntesis aditiva (permite explicar la obtención de un color a partir de la suma de los componentes de color), que permite representar un color mediante la mezcla por adición de los tres colores de luz primarios (rojo, verde y azul - <i>red, green and blue</i>). Si bien el propio modelo de color RGB no define por sí mismo lo que significa exactamente cada uno de los valores primarios, siendo que pueden existir colores notablemente diferentes en distintos dispositivos a pesar de usar el mismo color, esto es algo que no aplica para este caso, pues nos movemos siempre dentro del propio modelo.</p>
+
+<p>En computación, para indicar con qué proporción es mezclado cada color, se asigna un valor a cada uno de estos tres colores, de forma que el valor 0 indica que no interviene en la mezcla y, a medida que el valor aumenta, se entiende que aporta intensidad a ésta. Aunque el intervalo de valores podría ser cualquiera, es frecuente que cada color primario se codifique con un byte (8 bits). Así, de manera prácticamente estándar, la intensidad de cada uno de los componentes se mide según una escala del 0 al 255.</p>
+
+<p>De tal forma que el rojo se obtiene con (255, 0, 0), el verde con (0, 255, 0) y el azul con (0, 0, 255), obteniendo en cada caso un resultado monocromático. La ausencia de color -o negro- se obtiene cuando los tres componentes son 0: (0, 0, 0). Amarillo sería (255, 255, 0), cian (0, 255, 255) y magenta (255, 0, 255). El color blanco de forma mezclando en el nivel máximo los colores primarios, o sea, (255, 255, 255). En el caso de la presente web, contamos con un gris propio de (28, 28, 28). El lector puede usar un <a href="https://imagecolorpicker.com/es">color picker</a> para experimentar y jugar con estos colores.</p>
+
+<p>En términos más técnicos del tema objeto del artículo, invertir el color en RGB significa restar cada componente del color al valor máximo posible. Así:</p>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mrow>
+<mn>255</mn>
+<mo>-</mo>
+<mi>x</mi>
+<mo>=</mo>
+<mi>i</mi>
+</mrow>
+</math>
+
+<p>Donde <emb>x</emb> es el valor actual, e <emb>i</emb> el resultado invertido. Por ejemplo:</p>
+
+<p>De blanco a negro:</p>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mfenced open="(" close=")">
+<mtable>
+<mtr>
+<mtd><mn>(255</mn></mtd>
+<mtd><mn>255</mn></mtd>
+<mtd><mn>255)</mn></mtd>
+</mtr>
+</mtable>
+</mfenced>
+</math>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mrow>
+<mn>255</mn>
+<mo>-</mo>
+<mn>255</mn>
+<mo>=</mo>
+<mn>0</mn>
+</mrow>
+</math>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mfenced open="(" close=")">
+<mtable>
+<mtr>
+<mtd><mn>0</mn></mtd>
+<mtd><mn>0</mn></mtd>
+<mtd><mn>0</mn></mtd>
+</mtr>
+</mtable>
+</mfenced>
+</math>
+<p>De negro a blanco:</p>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mfenced open="(" close=")">
+<mtable>
+<mtr>
+<mtd><mn>(0</mn></mtd>
+<mtd><mn>0</mn></mtd>
+<mtd><mn>0)</mn></mtd>
+</mtr>
+</mtable>
+</mfenced>
+</math>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mrow>
+<mn>255</mn>
+<mo>-</mo>
+<mn>0</mn>
+<mo>=</mo>
+<mn>255</mn>
+</mrow>
+</math>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mfenced open="(" close=")">
+<mtable>
+<mtr>
+<mtd><mn>255</mn></mtd>
+<mtd><mn>255</mn></mtd>
+<mtd><mn>255</mn></mtd>
+</mtr>
+</mtable>
+</mfenced>
+</math>
+
+<p>Por lo que si necesito que la inversión del color de fondo corresponda con el RGB (28, 28, 28):</p>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mrow>
+<mn>255</mn>
+<mo>-</mo>
+<mi>x</mi>
+<mo>=</mo>
+<mn>28</mn>
+</mrow>
+</math>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mrow>
+<mi>x</mi>
+<mo>=</mo>
+<mn>227</mn>
+</mrow>
+</math>
+
+<p>La teoría de inversión de color RGB la tenemos clara. Sin embargo, no podemos indicar directamente que requerimos el valor (277, 277, 277) al fondo de una imagen para que se corresponda con éste en modo oscuro. Ya que lo requerimos es el valor o porcentaje de inversión necesaria para que se produzca el cálculo anterior transparentemente.</p>
+<p>Si el caso fuera invertir de blanco (255, 255, 255) a negro (0, 0, 0) y viceversa en todas las ocasiones, es decir, si mantenemos un fondo blanco, y negro en modo oscuro. Simplemente valdría con usar la unidad <emb>filter: invert(1);</emb> ó el porcentaje total <emb>filter: invert(100%);</emb>.</p>
+<p>Pero si requerimos de una inversión parcial, la fórmula sería:</p>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mrow>
+<mi>r</mi>
+<mo>=</mo>
+<mi>x</mi>
+<mo>(</mo>
+<mn>1</mn>
+<mo>-</mo>
+<mi>p</mi>
+<mo>)</mo>
+<mo>+</mo>
+<mo>(</mo>
+<mn>255</mn>
+<mo>-</mo>
+<mi>x</mi>
+<mo>)</mo>
+<mi>p</mi>
+</mrow>
+</math>
+
+<p>Donde <emb>r</emb> es el resultado deseado (o sea, 28), <emb>x</emb> el valor original (del blanco, 255) y <emb>p</emb> el porcentaje deseado. Desarrollamos:</p>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mrow>
+<mn>28</mn>
+<mo>=</mo>
+<mn>255</mn>
+<mo>(</mo>
+<mn>1</mn>
+<mo>-</mo>
+<mi>p</mi>
+<mo>)</mo>
+<mo>+</mo>
+<mo>(</mo>
+<mn>255</mn>
+<mo>-</mo>
+<mn>255</mn>
+<mo>)</mo>
+<mi>p</mi>
+</mrow>
+</math>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mrow>
+<mn>28</mn>
+<mo>=</mo>
+<mn>255</mn>
+<mo>*</mo>
+<mi>p</mi>
+<mo>0</mo>
+<mi>p</mi>
+</mrow>
+</math>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mrow>
+<mn>28</mn>
+<mo>=</mo>
+<mn>255</mn>
+<mo>*</mo>
+<mi>p</mi>
+</mrow>
+</math>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mrow>
+<mi>p</mi>
+<mo>=</mo>
+<mfrac>
+<mrow>
+<mn>28</mn>
+</mrow>
+<mrow>
+<mn>255</mn>
+</mrow>
+</mfrac>
+</mrow>
+</math>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mrow>
+<mi>p</mi>
+<mo>=</mo>
+<mn>0.109803921569</mn>
+</mrow>
+</math>
+
+<p>Finalmente, el valor <emb>p</emb> lo convertimos a porcentaje y restamos del total para obtener el valor deseado:</p>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mrow>
+<mn>0.109803921569</mn>
+<mo>*</mo>
+<mn>100</mn>
+<mo>=</mo>
+<mn>10.9803921569</mn>
+</mrow>
+</math>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+<mrow>
+<mn>100</mn>
+<mo>-</mo>
+<mn>10.9803921569</mn>
+<mo>=</mo>
+<mn>89.0196078431</mn>
+</mrow>
+</math>
+
+<p>Obtniendo así el filtro de inversión <emb>filter: invert(89.0196078431%);</emb>. He desarrollado un pequeño código que automatiza este cálculo:</p>
+<pre><code>#include <stdio.h>
+#include <stdlib.h>
+
+double inversion(int x);
+
+int main(int argc, char *argv[]) {
+ if (argc != 4) {
+ printf("Uso: %s r g b\n", argv[0]);
+ return 1;
+ }
+
+ int r = atoi(argv[1]);
+ int g = atoi(argv[2]);
+ int b = atoi(argv[3]);
+
+ printf("Valor RGB objetivo: (%d, %d, %d)\n", r, g, b);
+
+ inversion(r);
+ inversion(g);
+ inversion(b);
+
+ return 0;
+}
+
+double inversion(int x) {
+ double r = (double)x /255.0;
+ double p = 100.0 - (r * 100.0);
+ printf("%f\n", p);
+ return p;
+}</code></pre>
+<p>Obtniendo así el valor de inversión parcial que permite filtrar la imagen y que se mimetice con el fondo de una forma plenamente estética y armoniosa. He aquí un ejemplo de la imagen invertida para con el fondo actual (28, 28, 28) con un valor de filtro del 89.0196078431%:</p>
+<img style="display: inline-block; width: 49%; vertical-align: top;" src="RGB.png" />
+<img style="display: inline-block; width: 49%; vertical-align: top; filter: invert(89.0196078431%);" src="RGB.png" />
+<p>En computación, principalmente en algunos lenguajes como HTML, CSS o Javascript, se emplea la notación hexadecimal del color. Este sistema combina los tres códigos numéricos en dos dígitos hexadecimales para expresar las intensisdades de los colores primarios RGB. Es decir, es un apantallamiento del RGB.</p>
+<p>Así, como codificamos en hexadecimal, la base correspnde a la numeración del <emb>0</emb> al <emb>9</emb> y las seis letras <emb>a</emb>, <emb>b</emb>, <emb>c</emb>, <emb>d</emb>, <emb>e</emb>, y <emb>f</emb>. No corresponde a este artículo desarrollar la numeración hexadecimal. Entonces, la intensidad máxima es <emb>ff</emb>, que se corresponde con <emb>(15×16)+15=255</emb> en decimal. La nula, evidentemente es <emb>00</emb>. Así, por ejemplo el valor RGB (113, 97, 228) corresponde al valor hexadecimal <emb>#7161E4</emb>.</p>
+</body>
+</html>
+\ No newline at end of file
diff --git a/index.html b/index.html
@@ -33,6 +33,31 @@
<p class="info">22 de junio de 2026 · fjbalon</p><p>Un software que me gusta bastante de la caja de herramientas de suckless es slock, un bloqueador de pantalla minimalista; tan minimalista que yo creo que es el bloqueador de pantalla x más sencillo q...</p>
</a>
+<a href="./slackware-slackbuild/" class="article">
+ <p class="title">Anatomía de un SlackBuild</p>
+ <p class="info">12 de diciembre de 2025 · fjbalon</p><p>Como usuario de Slackware, he usado alguna vez scripts de SlackBuild para crear un paquete de software que pueda ser instalado fácil y limpiamente, y eliminado más tarde si es necesario con la misma...</p>
+</a>
+
+<a href="./http-darkmode/" class="article">
+ <p class="title">Algoritmo para determinar el grado del modo oscuro en imágenes invertidas</p>
+ <p class="info">11 de junio de 2024 · fjbalon</p><p>No son pocas las ocasiones en que los sitios web ofrecen, a través de código javascript y cookies, sistemas de switch (o conmutador, en cristiano) del sistema claro u oscuro. Por la salud visual de ...</p>
+</a>
+
+<a href="./slackware/" class="article">
+ <p class="title">De Slackware</p>
+ <p class="info">16 de marzo de 2024 · fjbalon</p><p>Slackware es la distribución de Linux más vieja y antigua que aún se mantiene con vida. Su lanzamiento inicial fue en 1993 y fue fundada por Patrick Volkerding, basándose en su momento en la distr...</p>
+</a>
+
+<a href="./sparse-files/" class="article">
+ <p class="title">Dispersión de archivos (sparse files) como método eficiente de uso del espacio</p>
+ <p class="info">20 de mayo de 2023 · fjbalon</p><p>En informática, un archivo disperso es un tipo que utiliza más eficientemente el espacio del sistema de archivos cuando los bloques asignados a los archivos están en su mayor parte vacíos. Esto se...</p>
+</a>
+
+<a href="./interpolacion-lineal/" class="article">
+ <p class="title">Interpolación lineal simple para calcular la temperatura de termorresistencias Pt100</p>
+ <p class="info">25 de noviembre de 2021 · fjbalon</p><p>El principio básico de un RTD es que su sensor de cable, hecho de un metal con una resistencia eléctrica conocida, cambia su valor de resistencia a medida que la temperatura sube o baja. Aunque las ...</p>
+</a>
+
<a href="./dwm-howto/" class="article">
<p class="title">Configuración y uso personal de dwm</p>
<p class="info">9 de octubre de 2021 · fjbalon</p><p>En orden a construir dwm necesita los archivos de cabecera de Xlib. Edite config.mk para localizar tu configuración local (dwm es instalado en usr/local por defecto). La instalación se realiza direc...</p>
@@ -43,6 +68,56 @@
<p class="info">8 de octubre de 2021 · fjbalon</p><p>Es cierto que Unix y Linux tienen algo esotérico, algo como de carácter iniciático. Hay una verdadera barrera entre el usuario y el verdadero emperador de su sistema, o el root. Estos sistemas son,...</p>
</a>
+<a href="./mechanic-keyboard/" class="article">
+ <p class="title">Montaje de teclado mecánico ortolineal y dividido</p>
+ <p class="info">17 de junio de 2021 · fjbalon</p><p>Dentro de mis intereses en informática y computación, un elemento que siempre me ha atraído mucho es el conocido «make it yourself»; el tener el máximo control posible, incluso sobre los perifé...</p>
+</a>
+
+<a href="./git-stagit/" class="article">
+ <p class="title">Externalización gráfica de servidor Git propio con stagit</p>
+ <p class="info">23 de noviembre de 2020 · fjbalon</p><p>A veces es agradable navegar por el registro del historial de git en un navegador web o en algún otro programa sin tener que mirar el repositorio local. Es además una forma de mantener un registro d...</p>
+</a>
+
+<a href="./git-server/" class="article">
+ <p class="title">Construcción de mi propio servidor Git</p>
+ <p class="info">22 de noviembre de 2020 · fjbalon</p><p>Aquí todos conocemos el software o protocolo desarrollado en inicio por Linus Torvalds: Git. Un sistema de control de versiones, que se constituye como una herramienta indispensable, a día de hoy, p...</p>
+</a>
+
+<a href="./swap/" class="article">
+ <p class="title">Sobre la necesidad de la memoria Swap</p>
+ <p class="info">27 de febrero de 2020 · fjbalon</p><p>El caso que hoy me ocupa, nace de la necesidad de apagar la memoria de intercambio (o swap) en mi equipo portátil para poder gestionar varias pruebas sobre clústers de kubernetes. Algo curioso, pues...</p>
+</a>
+
+<a href="./kernel-compression/" class="article">
+ <p class="title">Demostración empírica de tipo de compresión usada en el kernel de Linux</p>
+ <p class="info">19 de noviembre de 2019 · fjbalon</p><p>Para la realización de una práctica de preparación de LPIC-1/2, debía averiguar el tipo de compresión del kernel de Linux empleado en mi sistema. En ese momento, usando la distribución archlinux...</p>
+</a>
+
+<a href="./ssh-tunneling/" class="article">
+ <p class="title">SSH Tunneling</p>
+ <p class="info">28 de marzo de 2019 · fjbalon</p><p>El tunneling es un proceso por el que se utiliza el protocolo SSH para fortificar la comunicación entre otros protocolos inseguros, por ejemplo para realizar peticiones HTTP, SMTP, etc....</p>
+</a>
+
+<a href="./linus-torvalds-hijas/" class="article">
+ <p class="title">Las fechas de nacimiento de Torvalds y sus hijas en las cabeceras del kernel</p>
+ <p class="info">1 de marzo de 2019 · fjbalon</p><p>Me han propuesto un reto: encontrar las fechas de nacimiento de Torvalds y de sus tres tres hijas en las cabeceras del kernel. Es un easter egg que dejó Linus para los más curiosos. Vamos allá....</p>
+</a>
+
+<a href="./ssh/" class="article">
+ <p class="title">Robustecimiento y securización del protocolo SSH</p>
+ <p class="info">20 de febrero de 2019 · fjbalon</p><p>SSH es uno de los protocolos más interesantes de los que dispone el administrador de sistemas, permitiendo acceder a otros equipos de forma remota; pero sobretodo, de forma segura. Con SSH creamos un...</p>
+</a>
+
+<a href="./tor/" class="article">
+ <p class="title">Contextualización teórica sobre la técnica de Tor y sus problemas de seguridad</p>
+ <p class="info">26 de abril de 2018 · fjbalon</p><p>Tor son las siglas de The Onion Routing, algo que podríamos traducir al español como enrutamiento cebolla; denominado así por su criptografía en capas, como veremos más adelante. Se trata de un p...</p>
+</a>
+
+<a href="./about/" class="article">
+ <p class="title">|</p>
+ <p class="info"> · </p><p>...</p>
+</a>
+
</section>
</body>
</html>
diff --git a/interpolacion-lineal/index.html b/interpolacion-lineal/index.html
@@ -0,0 +1,203 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Interpolación lineal simple para calcular la temperatura de termorresistencias Pt100</title>
+<link rel="icon" type="image/png" href="/favicon.png" />
+<link rel="stylesheet" type="text/css" href="../article.css" />
+</head>
+<body>
+<header>
+<p class="title">Interpolación lineal simple para calcular la temperatura de termorresistencias Pt100</p>
+<p class="date">25 de noviembre de 2021 • fjbalon</p>
+</header>
+<p>El principio básico de un RTD es que su sensor de cable, hecho de un metal con una resistencia eléctrica conocida, cambia su valor de resistencia a medida que la temperatura sube o baja. Aunque las termorresistencias tienen ciertas limitaciones, que incluyen una temperatura de medición máxima de alrededor de 1,100°F (600°C), en general, son la solución de medición de temperatura ideal para una multitud de procesos.</p>
+<p>Los cables de detección en un RTD pueden estar hechos de níquel (Ni), cobre (Cu) o tungsteno (W), pero el platino (Pt) es, con mucho, el metal más popular usado en la actualidad. Es más caro que otros materiales, pero el platino tiene varias características que lo hacen particularmente adecuado para las mediciones de temperatura, que incluyen:</p>
+<ul>
+<li>Relación temperatura-resistencia casi lineal.</li>
+<li>Alta resistividad (59Ω/cmf en comparación con 36Ω/cmf para níquel).</li>
+<li>Resistencia eléctrica no degradable en el tiempo.</li>
+<li>Excelente estabilidad.</li>
+<li>Muy buena pasividad química.</li>
+<li>Alta resistencia a la contaminación.</li>
+</ul>
+<p>Entre los sensores RTD de platino, Pt100 y Pt1000 son los más comunes. Los sensores Pt100 tienen una resistencia nominal de 100Ω en el punto de hielo (0°C). La resistencia nominal de los sensores Pt1000 a 0°C es de 1.000Ω. La linealidad de la curva característica, el rango de temperatura de operación y el tiempo de respuesta son los mismos para ambos. El coeficiente de temperatura de resistencia es también el mismo.</p>
+<p>Sin embargo, debido a la diferente resistencia nominal, las lecturas de los sensores Pt1000 son mayores en un factor de 10 en comparación con los sensores Pt100. Esta diferencia se hace evidente cuando se comparan configuraciones de 2 cables, donde se aplica el error de medición del cable. Por ejemplo, el error de medición en un Pt100 podría ser <emb>+1.0ºC</emb>, y en el mismo diseño, un Pt1000 podría ser <emb>+0.1ºC</emb>.</p>
+<p>Tras contextualizar expongo el problema: leyendo mediante modbus los datos recibidos de un par de termorresistencias Pt100, me percaté que recibía, evidentemente, los datos raw. Pero no encontraba en documentación de los sensores ni en Internet el factor de conversión de esta unidad a grados. Mi única pista era la interfaz web del aparato, que establecía el rango de limitación como <emb>-100~100ºC</emb>.</p>
+<p>Tengo entonces, por comprobación o por determinación (<emb>"By default, the High Alarm value is +32767 (0x7FFF) and the low alarm value is -32768 (0xFFFF)"</emb>) que el valor límite absoluto es <emb>32768</emb>; siendo entonces un rango de <emb>-32768~32767</emb>.</p>
+<pre><code>./modpoll -r2 -1 -t3 172.16.20.13
+
+Protocol configuration: MODBUS/TCP, FC4
+Slave configuration...: address = 1, start reference = 2, count = 1
+Communication.........: 172.16.20.13, port 502, t/o 1.00 s, poll rate 1000 ms
+Data type.............: 16-bit register, input register table
+
+-- Polling slave...
+[2]: 6372
+
+
+./modpoll -r3 -1 -t3 172.16.20.13
+
+Protocol configuration: MODBUS/TCP, FC4
+Slave configuration...: address = 1, start reference = 3, count = 1
+Communication.........: 172.16.20.13, port 502, t/o 1.00 s, poll rate 1000 ms
+Data type.............: 16-bit register, input register table
+
+-- Polling slave...
+[3]: 8388
+</code></pre>
+<p>Y obteniendo los valores raw de cada sensor, necesitaría reproducir lo más fiel posible una función a la representada con estos valores. Para ello, realizaría una interpolación lineal simple, consiste en trazar una recta que pasa por dos puntos conocidos <emb>y = r(x)</emb> y calcular los valores intermedios según esta recta.</p>
+<p>La ecuación de una recta conocido dos puntos <emb>(x1,y1)</emb> y <emb>(x2,y2)</emb> es:</p>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\frac{(y-y_{1})}{(y_{2}-y_{1})}=\frac{(x-y_{1})}{(x_{2}-x_{1})}" display="block">
+ <mrow>
+ <mfrac>
+ <mrow>
+ <mo stretchy="false">(</mo>
+ <mrow>
+ <mi>y</mi>
+ <mo>-</mo>
+ <msub>
+ <mi>y</mi>
+ <mn>1</mn>
+ </msub>
+ </mrow>
+ <mo stretchy="false">)</mo>
+ </mrow>
+ <mrow>
+ <mo stretchy="false">(</mo>
+ <mrow>
+ <msub>
+ <mi>y</mi>
+ <mn>2</mn>
+ </msub>
+ <mo>-</mo>
+ <msub>
+ <mi>y</mi>
+ <mn>1</mn>
+ </msub>
+ </mrow>
+ <mo stretchy="false">)</mo>
+ </mrow>
+ </mfrac>
+ <mo>=</mo>
+ <mfrac>
+ <mrow>
+ <mo stretchy="false">(</mo>
+ <mrow>
+ <mi>x</mi>
+ <mo>-</mo>
+ <msub>
+ <mi>y</mi>
+ <mn>1</mn>
+ </msub>
+ </mrow>
+ <mo stretchy="false">)</mo>
+ </mrow>
+ <mrow>
+ <mo stretchy="false">(</mo>
+ <mrow>
+ <msub>
+ <mi>x</mi>
+ <mn>2</mn>
+ </msub>
+ <mo>-</mo>
+ <msub>
+ <mi>x</mi>
+ <mn>1</mn>
+ </msub>
+ </mrow>
+ <mo stretchy="false">)</mo>
+ </mrow>
+ </mfrac>
+ </mrow>
+</math>
+<p>Que despejando la y, valor que querríamos obtener, tenemos:</p>
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="y=y_{1}+\frac{(y_{2}-y_{1})}{(x_{2}-x_{1})}(x-x_{1})" display="block">
+ <mrow>
+ <mi>y</mi>
+ <mo>=</mo>
+ <mrow>
+ <msub>
+ <mi>y</mi>
+ <mn>1</mn>
+ </msub>
+ <mo>+</mo>
+ <mrow>
+ <mfrac>
+ <mrow>
+ <mo stretchy="false">(</mo>
+ <mrow>
+ <msub>
+ <mi>y</mi>
+ <mn>2</mn>
+ </msub>
+ <mo>-</mo>
+ <msub>
+ <mi>y</mi>
+ <mn>1</mn>
+ </msub>
+ </mrow>
+ <mo stretchy="false">)</mo>
+ </mrow>
+ <mrow>
+ <mo stretchy="false">(</mo>
+ <mrow>
+ <msub>
+ <mi>x</mi>
+ <mn>2</mn>
+ </msub>
+ <mo>-</mo>
+ <msub>
+ <mi>x</mi>
+ <mn>1</mn>
+ </msub>
+ </mrow>
+ <mo stretchy="false">)</mo>
+ </mrow>
+ </mfrac>
+ <mo></mo>
+ <mrow>
+ <mo stretchy="false">(</mo>
+ <mrow>
+ <mi>x</mi>
+ <mo>-</mo>
+ <msub>
+ <mi>x</mi>
+ <mn>1</mn>
+ </msub>
+ </mrow>
+ <mo stretchy="false">)</mo>
+ </mrow>
+ </mrow>
+ </mrow>
+ </mrow>
+</math>
+<img class="color-invertible" style="width: 40%;" src="resources/grafico-interpolacion-lineal.png" />
+<p>Por deformación profesional, en lugar de hacer estos cálculos a mano he desarrollado un pequeño programa en C que calculase esta ecuación, donde los valores de x corresponden a los valores raw y los valores de y a los valores en grados; siendo la y precisamente el valor a obtener:</p>
+<pre><code>#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc,char *argv[])
+{
+ float x, x1 = -32768.0, x2 = 32768.0;
+ float y, y1 = -100.0, y2 = 100.0;
+
+ if( argc > 1 ) {
+ x = atof(argv[1]);
+ }
+
+ y = y1 + ((y2 - y1)/(x2 - x1)) * (x - x1);
+
+ printf("Interpolación lineal = %f\n",y);
+ return(0);
+}</code></pre>
+<p>De tal forma que, pasando como parámetro el valor obtenido por modbus, y estando x1, x2, y1, e y2 calibrados en código, sólo cabría obtener la variable esperada y.</p>
+<pre><code>./interpolacion-lineal 6372
+Interpolación lineal = 19.447624
+./interpolacion-lineal 8388
+Interpolación lineal = 25.600060</code></pre>
+<p>Es decir, obtendríamos 19,45ºC y 25,60ºC, respectivamente.</p>
+</body>
+</html>
+\ No newline at end of file
diff --git a/interpolacion-lineal/resources/grafico-interpolacion-lineal.png b/interpolacion-lineal/resources/grafico-interpolacion-lineal.png
Binary files differ.
diff --git a/kernel-compression/index.html b/kernel-compression/index.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Demostración empírica de tipo de compresión usada en el kernel de Linux</title>
+<link rel="icon" type="image/png" href="/favicon.png" />
+<link rel="stylesheet" type="text/css" href="../article.css" />
+</head>
+<body>
+<header>
+<p class="title">Demostración empírica de tipo de compresión usada en el kernel de Linux</p>
+<p class="date">19 de noviembre de 2019 • fjbalon</p>
+</header>
+<p>Para la realización de una práctica de preparación de LPIC-1/2, debía averiguar el tipo de compresión del kernel de Linux empleado en mi sistema. En ese momento, usando la distribución <emb>archlinux</emb>.</p>
+<p>Ejecutando file sobre el fichero de kernel obtengo:</p>
+<pre><code>$ file /boot/vmlinuz-linux
+/boot/vmlinuz-linux: Linux kernel x86 boot executable bzImage, version 5.14.16-arch1-1 (linux@archlinux) #1 \
+SMP PREEMPT Tue, 02 Nov 2021 22:22:59 +0000, RO-rootFS, swap_dev 0X9, Normal VGA</code></pre>
+<p>Y revisando la documentación teórica, observo que bzImage debería ir comprimido por <emb>gzip</emb> (<emb>z</emb>). Véase <a href="http://www.linfo.org/vmlinuz.html">vmlinuz.html</a>. De hecho, existe la idea errónea popular de que el prefijo <emb>bz</emb> significa que se utiliza la compresión <emb>bzip2</emb>, pero este no es el caso, por lo que el bz en bzImage no tiene relación con <emb>bzip2</emb>, y <emb>bzImage</emb> no tiene que ser comprimido con <emb>bzip2</emb>, como algunas veces se postula. De hecho, el modo de compresión predeterminado del kernel sigue siendo <emb>gzip</emb>, y hay pocas razones para usar bzip2 hoy en día: es más lento que <emb>LZMA</emb> y <emb>xz</emb>, pero no se comprime tan bien.</p>
+<h2>Pero, ¿cómo puedo probarlo empíricamente?</h2>
+<p>Para determinar de manera concluyente qué compresión se utilizó para una imagen dada del kernel, sin necesidad de ejecutarla o encontrar su configuración, podemos seguir el enfoque utilizado por el propio script <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/scripts/extract-vmlinux">extract-vmlinux</a> del kernel.</p>
+<p>Buscando primero la firma del compresor en la imagen:</p>
+<ul>
+<li>gunzip: \037\213\010</li>
+<li>xz: \3757zXZ\000</li>
+<li>bzip2: BZh</li>
+<li>lzma: \135\0\0\0</li>
+<li>lzo: \211\114\132</li>
+<li>lz4: \002!L\030</li>
+<li>zstd: (\265/\375</li>
+</ul>
+<p>Pretendiendo extraer los datos de la imagen, comenzando por el desplazamiento de cualquier firma que haya encontrado y comprobando que el resultado (si lo hubiera) sea una imagen de ELF. Con una breve adaptación del script -por <a href="https://gist.github.com/skitt/288c0c52b51b5863947a5d6c1180c9f3">Stephen Kitt</a>-. para sólo reportar el tipo de compresión, obtenemos sencillamente el tipo:</p>
+<pre><code>4c4
+< # extract-vmlinux - Extract uncompressed vmlinux from a kernel image
+---
+> # check-vmlinux - Identify compression used for a kernel image
+8d7
+< #
+9a9
+> # © 2019 Stephen Kitt <steve@sk2.org>
+20,22c20,22
+< cat $1
+< exit 0
+< }
+---
+> echo The image was compressed using $2
+> exit 0
+> }
+34c34
+< check_vmlinux $tmp
+---
+> check_vmlinux $tmp $4
+52,58c52,58
+< try_decompress '\037\213\010' xy gunzip
+< try_decompress '\3757zXZ\000' abcde unxz
+< try_decompress 'BZh' xy bunzip2
+< try_decompress '\135\0\0\0' xxx unlzma
+< try_decompress '\211\114\132' xy 'lzop -d'
+< try_decompress '\002!L\030' xxx 'lz4 -d'
+< try_decompress '(\265/\375' xxx unzstd
+---
+> try_decompress '\037\213\010' xy gunzip gzip
+> try_decompress '\3757zXZ\000' abcde unxz xz
+> try_decompress 'BZh' xy bunzip2 bzip2
+> try_decompress '\135\0\0\0' xxx unlzma lzma
+> try_decompress '\211\114\132' xy 'lzop -d' lzop
+> try_decompress '\002!L\030' xxx 'lz4 -d' lz4
+> try_decompress '(\265/\375' xxx unzstd zstd
+61c61
+< check_vmlinux $img
+---
+> check_vmlinux $img none
+
+--------------------------------------------------------------------
+
+./nuevo /boot/vmlinuz-linux
+The image was compressed using zstd</code></pre>
+<p>Otra forma de validarlo es comprobar qué métodos de compresión soporta el núcleo. Sólo puede haber uno seleccionado, el cual determinará el algoritmo empleado:</p>
+
+<pre><code>zgrep CONFIG_KERNEL_ /proc/config.gz
+# CONFIG_KERNEL_GZIP is not set
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_XZ is not set
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_KERNEL_LZ4 is not set
+CONFIG_KERNEL_ZSTD=y</code></pre>
+<p>Como conclusión, a pesar de que en la teoría, por defecto es usado el algoritmo de gzip, en ocasiones como la que ocupa al caso actual no se corresponde con ésta, requiriendo una demostración concluyente antes de tomar conclusiones erróneas fundamentadas únicamente en la teoría.</p>
+
+</body>
+</html>
+\ No newline at end of file
diff --git a/linus-torvalds-hijas/index.html b/linus-torvalds-hijas/index.html
@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Las fechas de nacimiento de Torvalds y sus hijas en las cabeceras del kernel</title>
+<link rel="icon" type="image/png" href="/favicon.png" />
+<link rel="stylesheet" type="text/css" href="../article.css" />
+</head>
+<body>
+<header>
+<p class="title">Las fechas de nacimiento de Torvalds y sus hijas en las cabeceras del kernel</p>
+<p class="date">1 de marzo de 2019 • fjbalon</p>
+</header>
+<p>Me han propuesto un reto: encontrar las fechas de nacimiento de Torvalds y de sus tres tres hijas en las cabeceras del kernel. Es un easter egg que dejó Linus para los más curiosos. Vamos allá.</p>
+<p>Encontrar las fechas es relativamente sencillo para quien sabe dónde buscar. No es mi caso, que tras una breve búsqueda en Internet identifiqué la localización de dichas fechas en la ruta /usr/include/linux/, encontrándose con la extensión .h. Es fácilmente localizable utilizando la conocida herramienta grep y buscando las cadenas de texto 'LINUX REBOOT MAGIC'.</p>
+<pre><code># grep LINUX_REBOOT_MAGIC /usr/include/linux/*.h
+/usr/include/linux/reboot.h:#define LINUX_REBOOT_MAGIC1 0xfee1dead
+/usr/include/linux/reboot.h:#define LINUX_REBOOT_MAGIC2 672274793
+/usr/include/linux/reboot.h:#define LINUX_REBOOT_MAGIC2A 85072278
+/usr/include/linux/reboot.h:#define LINUX_REBOOT_MAGIC2B 369367448
+/usr/include/linux/reboot.h:#define LINUX_REBOOT_MAGIC2C 537993216</code></pre>
+<p>Encontramos entonces que nos devuelve una información en un formato quizás extraño, que corresponde a los siguientes ¿enteros?: 672274793, 85072278, 369367448 y 537993216.</p>
+<p>En un principio supuse que se trataba de timestamp, un formato de tiempo utilizado frecuentemente por los sistemas Unix y derivados; éste cuenta la cantidad de segundos transcurridos desde el EPOCH (fecha 1970-01-01 00:00:00 GMT). Por lo que, transformándolo con una simple línea Perl a formato localtime bastaría.</p>
+<pre><code>$ perl -e 'print localtime(672274793). "\n";'
+Mon Apr 22 00:59:53 1991
+$ perl -e 'print localtime(85072278). "\n";'
+Mon Sep 11 16:11:18 1972
+$ perl -e 'print localtime(369367448). "\n";'
+Tue Sep 15 04:04:08 1981
+$ perl -e 'print localtime(537993216). "\n";'
+Sun Jan 18 19:33:36 1987</code></pre>
+<p>Obtenemos las fechas: 22/04/1991, 11/09/1972, 15/09/1981 y 18/01/1987.</p>
+<p>¿He conseguido el reto? Nada más lejos... Al corroborar la fecha de nacimiento de Linus Torvalds hay algo que no me cuadra. Torvalds nació el 28 de diciembre de 1969. La primera fecha podría pasar; pero las 3 siguientes que correspondieran a las fechas de nacimiento de las 3 hijas me hacen pensar: ¿Tordvals tuvo su primera hija con 3 años?. Algo no cuadra.</p>
+<p>Tras un tiempo de investigación he dado con la tecla: es necesario pasar a hexadecimal para poder leer la fecha. Siendo</p>
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="0x672274793=2812196928/12/1969" display="block">
+ <mrow>
+ <mrow>
+ <mn>0</mn>
+ <mo></mo>
+ <mi>x</mi>
+ <mo></mo>
+ <mn>672274793</mn>
+ </mrow>
+ <mo>=</mo>
+ <mrow>
+ <mn>28121969; 28</mn>
+ <mo>/</mo>
+ <mn>12</mn>
+ <mo>/</mo>
+ <mn>1969</mn>
+ </mrow>
+ </mrow>
+</math>
+<p>el nacimiento de Linus Tordvals,</p>
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="0x85072278=51219965/12/1996" display="block">
+ <mrow>
+ <mrow>
+ <mn>0</mn>
+ <mo></mo>
+ <mi>x</mi>
+ <mo></mo>
+ <mn>85072278</mn>
+ </mrow>
+ <mo>=</mo>
+ <mrow>
+ <mn>5121996; 5</mn>
+ <mo>/</mo>
+ <mn>12</mn>
+ <mo>/</mo>
+ <mn>1996</mn>
+ </mrow>
+ </mrow>
+</math>
+<p>el nacimiento de Patricia Miranda,</p>
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="0x367369448=1604199816/04/1998" display="block">
+ <mrow>
+ <mrow>
+ <mn>0</mn>
+ <mo></mo>
+ <mi>x</mi>
+ <mo></mo>
+ <mn>367369448</mn>
+ </mrow>
+ <mo>=</mo>
+ <mrow>
+ <mn>16041998; 16</mn>
+ <mo>/</mo>
+ <mn>04</mn>
+ <mo>/</mo>
+ <mn>1998</mn>
+ </mrow>
+ </mrow>
+</math>
+<p>el nacimiento de Daniela Yolanda y</p>
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="0x537993216=2012200020/12/2000" display="block">
+ <mrow>
+ <mrow>
+ <mn>0</mn>
+ <mo></mo>
+ <mi>x</mi>
+ <mo></mo>
+ <mn>537993216</mn>
+ </mrow>
+ <mo>=</mo>
+ <mrow>
+ <mn>20122000; 20</mn>
+ <mo>/</mo>
+ <mn>12</mn>
+ <mo>/</mo>
+ <mn>2000</mn>
+ </mrow>
+ </mrow>
+</math>
+<p>el nacimiento de Celeste Amanda, las 3 hijas de Tordvals respectivamente.</p>
+<p>Estos elementos se tratan de números mágicos; es decir cadenas de caracteres alfanuméricos que identifican un archivo (ID). El objetivo de estos números mágicos concretos, grosso modo, es el de proteger la llamada verdadera REBOOT del sistema, ya que es una llamada destructiva que puede arrojar graves errores de programa. Linux ofrece una protección extra de esta forma.</p>
+</body>
+</html>
+\ No newline at end of file
diff --git a/mechanic-keyboard/imagen1.jpeg b/mechanic-keyboard/imagen1.jpeg
Binary files differ.
diff --git a/mechanic-keyboard/imagen10.jpeg b/mechanic-keyboard/imagen10.jpeg
Binary files differ.
diff --git a/mechanic-keyboard/imagen11.jpeg b/mechanic-keyboard/imagen11.jpeg
Binary files differ.
diff --git a/mechanic-keyboard/imagen12.jpeg b/mechanic-keyboard/imagen12.jpeg
Binary files differ.
diff --git a/mechanic-keyboard/imagen2.jpeg b/mechanic-keyboard/imagen2.jpeg
Binary files differ.
diff --git a/mechanic-keyboard/imagen3.jpeg b/mechanic-keyboard/imagen3.jpeg
Binary files differ.
diff --git a/mechanic-keyboard/imagen4.jpeg b/mechanic-keyboard/imagen4.jpeg
Binary files differ.
diff --git a/mechanic-keyboard/imagen5.jpeg b/mechanic-keyboard/imagen5.jpeg
Binary files differ.
diff --git a/mechanic-keyboard/imagen6.jpeg b/mechanic-keyboard/imagen6.jpeg
Binary files differ.
diff --git a/mechanic-keyboard/imagen7.jpeg b/mechanic-keyboard/imagen7.jpeg
Binary files differ.
diff --git a/mechanic-keyboard/imagen8.png b/mechanic-keyboard/imagen8.png
Binary files differ.
diff --git a/mechanic-keyboard/imagen9.jpeg b/mechanic-keyboard/imagen9.jpeg
Binary files differ.
diff --git a/mechanic-keyboard/index.html b/mechanic-keyboard/index.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Montaje de teclado mecánico ortolineal y dividido</title>
+<link rel="icon" type="image/png" href="/favicon.png" />
+<link rel="stylesheet" type="text/css" href="../article.css" />
+</head>
+<body>
+<header>
+<p class="title">Montaje de teclado mecánico ortolineal y dividido</p>
+<p class="date">17 de junio de 2021 • fjbalon</p>
+</header>
+<p>Dentro de mis intereses en informática y computación, un elemento que siempre me ha atraído mucho es el conocido «make it yourself»; el tener el máximo control posible, incluso sobre los periféricos que utilizo. Además de ser un motivo estético y de aprendizaje soberanamente interesante para mí.</p>
+<p>Uno de estos elementos es el teclado mecánico. Hace ya un tiempo compré, en <a href="https://www.littlekeyboards.com/">Little Keyboards</a>, dos PCB para hacer un teclado mecánico, ortolineal y dividido (un teclado para cada mano). Usé, de hecho, la PCB <a href="https://github.com/MakotoKurauchi/helix">Helix</a>, diseñada por Makoto Kurauchi. Estéticamente, preciosa:</p>
+<img src="imagen1.jpeg" />
+<h2>Componentes</h2>
+<p>Entonces, me hice con los componentes necesarios: PCBs, conectores TTRS Jack, cable TTRS, reset switches, diodos, Cherry MX Blue, Kailh Choc Low Profile Switches -en blanco-… Más exactamente:</p>
+<ul>
+<li>Helix Hotswap PCB (2)</li>
+<li>TTRS Jack (2)</li>
+<li>Reset switch (2)</li>
+<li>Diodo (64)</li>
+<li>Kailh MX Hotswap Socket (64)</li>
+<li>Pro Microcontroller (2)</li>
+<li>Clear Helix Case</li>
+<li>Cherry MX Blue (64)</li>
+<li>Keycaps (64)</li>
+<li>Cable TRRS</li>
+<li>Cable USB-C a USB2.0</li>
+<li>Oled Screen (2)</li>
+</ul>
+<p>Las herramientas que utilicé para su montaje fueron una estación de soldadura de 80W de estaño (40-480ºC), Isopropanol o alcohol isopropílico y un polímetro digital.</p>
+<p>Y, como “cerebros”, los microcontroladores <a href="https://www.littlekeyboards.com/collections/mcus/products/elite-c-v3">MCU Elite-Cv4</a>. Éstos fueron diseñados como alternativa al más conocido MCU Pro Micro, pero añadiéndole cargador de arranque DFU y conector USB Tipo C. Además, le añado a cada uno una <a href="https://www.littlekeyboards.com/collections/oled-screens/products/oled-screen">pantalla OLED 128x32</a>.</p>
+<img style="width: 60%;" src="imagen2.jpeg" />
+<p>Una alternativa muy buena, por si a alguien le interesara, es el <a href="https://customkbd.com/products/sea-micro-pro-micro-alternative">sea-micro</a>, que cuenta con conector USB Tipo C y botón reset incorporado.</p>
+<h2>Soldadura de componentes principales de control</h2>
+<p>Algunas fotos del proceso de soldadura:</p>
+<img style="width: 60%;" src="imagen3.jpeg" />
+<img style="width: 60%;" src="imagen4.jpeg" />
+<h2>Flash de firmware en el microcontrolador</h2>
+<p>Después, un proceso muy divertido y entretenido es el flashing de firmware en el microcontrolador.</p>
+<p>Para ello, debemos conectar mediante USB el microcontrolador. Se encenderá el led que indica que recibe corriente.</p>
+<img style="width: 60%;" src="imagen5.jpeg" />
+<p>La herramienta que yo utilicé es QMK, basado en Python, y que trae un código por defecto para la placa Helix.</p>
+<pre><code>python3 -m pip install --user qmk
+export PATH=$PATH:/home/ssh/.local/bin
+qmk setup
+cd qmk_firmware
+make helix/rev3_5rows:default:clean
+make helix/rev3_5rows:default:dfu
+qmk compile -kb helix/rev3_5rows -km default</code></pre>
+<img src="imagen6.jpeg" />
+<p>Una ventaja añadida del sea-micro es que cuenta con botón reset integrado. Esto nos permite flashear el firmware sin necesidad de puente hardware o estar soldado ya en PCB de teclado.</p>
+<img style="width: 60%;" src="imagen7.jpeg" />
+<h2>Soldadura de diodos</h2>
+<p>Necesitaremos 64 diodos, uno por cada tecla. Son un componente electrónico de dos terminales que permite la circulación de la corriente eléctrica a través de él en un solo sentido, bloqueando el paso si la corriente circula en sentido contrario, no solo sirve para la circulación de corriente eléctrica sino que este la controla y resiste.</p>
+<img style="width: 10%;" src="imagen8.png" />
+<img style="width: 60%;" src="imagen9.jpeg" />
+<h2>Soldadura de hotswaps</h2>
+<img style="width: 60%;" src="imagen10.jpeg" />
+<img src="imagen11.jpeg" />
+<p>Aquí una foto del estado final después de ensamblar todo. Les cambié los switches por unos de otro tipo, de forma que quedaran más bajas y ocupasen menos espacio de altura.</p>
+<p>Desgraciadamente, en una mudanza se me rompieron dos teclas. Estoy pendiente de sustituirlas.</p>
+<img src="imagen12.jpeg" />
+</body>
+</html>
+\ No newline at end of file
diff --git a/slackware-slackbuild/index.html b/slackware-slackbuild/index.html
@@ -0,0 +1,181 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Anatomía de un SlackBuild</title>
+<link rel="icon" type="image/png" href="/favicon.png" />
+<link rel="stylesheet" type="text/css" href="../article.css" />
+</head>
+<body>
+<header>
+<p class="title">Anatomía de un SlackBuild</p>
+<p class="date">12 de diciembre de 2025 • fjbalon</p>
+</header>
+<p>Como usuario de Slackware, he usado alguna vez scripts de SlackBuild para crear un paquete de software que pueda ser instalado fácil y limpiamente, y eliminado más tarde si es necesario con la misma facilidad y limpieza. Lo veremos en más profundidad más adelante, pero resumidamente sabemos que un SlackBuild es un script de shell que nos permite compilar e instalar paquetes desde el código fuente, creando un paquete -generalmente <emb>txz</emb>, aunque también <emb>tgz</emb>- y se instala mediante la herramienta nativa de Slackware <emb>installpkg</emb>. Se distribuyen principalmente en el repositorio oficial de <a href="https://slackbuilds.org">slackbuilds.org</a>.</p>
+<p>Al final, los SlackBuilds constituyen la forma oficial, digamos, de instalar software que mno viene en los repositorios base de Slackware.</p>
+<p>Existen diferentes enfoques de un script de SlackBuild, por ejemplo <i>Alien Bob</i> tiene su muy útil <a href="https://alien.slackbook.org/AST/">creador de SlackBuilds</a> y, en términos generales, lo respetaremos. Y como ejemplo mediante el cual encarnar lo que vamos a describir, usaré el paquete <a href="https://slackbuilds.org/repository/15.0/system/ksh-openbsd/">ksh-openbsd</a>. La descarga, generalmente, viene en un paquete comprimido <emb>.tar.gz</emb>, que se destarea y descomprime con <emb>tar xzvf</emb>, siendo el contenido del directorio:</p>
+<pre><code>ls
+doinst.sh ksh-openbsd.info ksh-openbsd.SlackBuild README slack-desc</code></pre>
+<p>Siendo el que nos interesa realmente el script <emb>ksh-openbsd.SlackBuild</emb> (téngase en cuenta que he eliminado comentarios para una mejor legibilidad):</p>
+<pre><code>#!/bin/bash
+
+cd $(dirname $0) ; CWD=$(pwd)
+
+PRGNAM=ksh-openbsd
+VERSION=${VERSION:-20190804}
+BUILD=${BUILD:-1}
+TAG=${TAG:-_SBo}
+PKGTYPE=${PKGTYPE:-tgz}
+
+if [ -z "$ARCH" ]; then
+ case "$( uname -m )" in
+ i?86) ARCH=i586 ;;
+ arm*) ARCH=arm ;;
+ *) ARCH=$( uname -m ) ;;
+ esac
+fi
+
+if [ ! -z "${PRINT_PACKAGE_NAME}" ]; then
+ echo "$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE"
+ exit 0
+fi
+
+TMP=${TMP:-/tmp/SBo}
+PKG=$TMP/package-$PRGNAM
+OUTPUT=${OUTPUT:-/tmp}
+
+if [ "${ARCH}" == "i586" ];then
+ SLKCFLAGS='-march=i586 -mtune=i686'
+ LIBDIRSUFFIX=""
+elif [ "$ARCH" == "i686" ]; then
+ SLKCFLAGS="-march=i686 -mtune=i686"
+ LIBDIRSUFFIX=""
+elif [ "${ARCH}" == "x86_64" ];then
+ SLKCFLAGS='-fPIC'
+ LIBDIRSUFFIX="64"
+else
+ SLKCFLAGS="-O2"
+ LIBDIRSUFFIX=""
+fi
+
+set -e
+
+rm -Rf $PKG
+mkdir -p $TMP $PKG $OUTPUT
+cd $TMP
+rm -Rf $PRGNAM-$VERSION
+tar xvf $CWD/$PRGNAM-$VERSION.tar.gz
+cd $PRGNAM-$VERSION
+chown -R root:root .
+find -L . \
+ \( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 -o -perm 511 \) \
+ -exec chmod 755 {} \+ -o \
+ \( -perm 666 -o -perm 664 -o -perm 600 -o -perm 444 -o -perm 440 -o -perm 400 \) \
+ -exec chmod 644 {} \+
+
+CFLAGS="$SLKCFLAGS $(getconf LFS_CFLAGS)" make
+
+case "$(ps -o stat= -p $$)" in
+ *+*) make check ;; # running in foreground
+ *) echo '*** Not running "make check" because we are in the background.' ;;
+esac
+
+make install DESTDIR=$PKG
+
+if [ -n "${PDKSH_BINNAME}" ];then
+ mv $PKG/bin/pdksh $PKG/bin/"${PDKSH_BINNAME}"
+ mv $PKG/usr/man/man1/pdksh.1 $PKG/usr/man/man1/"${PDKSH_BINNAME}".1
+ mv $PKG/usr/man/man1/pdksh-sh.1 $PKG/usr/man/man1/"${PDKSH_BINNAME}"-sh.1
+fi
+BINNAME=${PDKSH_BINNAME:-pdksh}
+
+strip --strip-unneeded $PKG/bin/"${BINNAME}"
+gzip -9 $PKG/usr/man/man1/"${BINNAME}".1
+gzip -9 $PKG/usr/man/man1/"${BINNAME}"-sh.1
+
+mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
+cp -a \
+ Changelog.ksh-openbsd LEGAL README \
+ $PKG/usr/doc/$PRGNAM-$VERSION
+cp $CWD/README $PKG/usr/doc/$PRGNAM-$VERSION/README.ksh-openbsd
+cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
+
+mkdir -p $PKG/install</code></pre>
+<p>Tras el <i>shebang</i> definimos las variables principales del paquete, como son <emb>PRGNAM</emb> (nombre del paquete, o sea, <emb>ksh-openbsd</emb>), <emb>VERSION</emb> (versión del software), <emb>BUILD</emb> (número de build del paquete Slackware, por defecto 1), <emb>TAG</emb> (etiqueta que se añade al paquete, como <emb>_SBo = SlackBuilds.org</emb>) y <emb>PKGTYPE</emb> (tipo de paquete, <emb>tgz</emb> en este caso).</p>
+<pre><code>if [ -z "$ARCH" ]; then
+ case "$( uname -m )" in
+ i?86) ARCH=i586 ;;
+ arm*) ARCH=arm ;;
+ *) ARCH=$( uname -m ) ;;
+ esac
+fi</code></pre>
+<p>Detectamos automáticamente la arquitectura del equipo si el usuario no la tiene
+definida.</p>
+<pre><code>if [ ! -z "${PRINT_PACKAGE_NAME}" ]; then
+ echo "$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE"
+ exit 0
+fi</code></pre>
+<p>Es una parte muy útil para herramientas de gestión de paquetes como <emb>sbopkg</emb> o <emb>sbotools</emb>. Si la variable <emb>PRINT_PACKAGE_NAME</emb> está definida, aunque vacía, el script imprimirá el nombre completo del paquete (<emb>ksh-openbsd-20190804-x86_64-1_SBo.tgz</emb>). Esto permite a los gestores de paquetes saber el nombre sin tener que construir todo.</p>
+<p>Después definirá los entornos de trabajo en <emb>TMP</emb> (por defecto <emb>/tmp/SBo</emb>), <emb>PKG</emb> (directorio donde se va a instalar el software en la fase de compilación) y <emb>OUTPUT</emb> (dónde se almacenará el <emb>.tgz</emb> final).</p>
+<pre><code>if [ "${ARCH}" == "i586" ];then
+ SLKCFLAGS='-march=i586 -mtune=i686'
+ LIBDIRSUFFIX=""
+elif [ "$ARCH" == "i686" ]; then
+ SLKCFLAGS="-march=i686 -mtune=i686"
+ LIBDIRSUFFIX=""
+elif [ "${ARCH}" == "x86_64" ];then
+ SLKCFLAGS='-fPIC'
+ LIBDIRSUFFIX="64"
+else
+ SLKCFLAGS="-O2"
+ LIBDIRSUFFIX=""
+fi</code></pre>
+<p>En este punto definimos las variables <emb>SLKCFLAGS</emb> y <emb>LIBDIRSUFFIX</emb>, utilizadas para optimización en función de la arquitectura previamente reconocida; y para la toma de decisión del uso del directorio <emb>/usr/lib</emb> o <emb>/usr/lib64</emb>, en función -de nuevo- de la arquitectura.</p>
+<p>A partir de aquí podemos decir que la técnica se inicia, una vez realizadas las parametrizaciones técnicas iniciales. La línea que contiene <emb>set -e</emb> indica al intérprete que si cualquier comando devuelve un error (código de salida distinto de 0), el script se detiene inmediatamente. Es una medida de seguridad muy común en este tipo de scripts.</p>
+<pre><code>rm -Rf $PKG
+mkdir -p $TMP $PKG $OUTPUT
+cd $TMP
+rm -Rf $PRGNAM-$VERSION
+tar xvf $CWD/$PRGNAM-$VERSION.tar.gz
+cd $PRGNAM-$VERSION
+chown -R root:root .
+find -L . \
+ \( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 -o -perm 511 \) \
+ -exec chmod 755 {} \+ -o \
+ \( -perm 666 -o -perm 664 -o -perm 600 -o -perm 444 -o -perm 440 -o -perm 400 \) \
+ -exec chmod 644 {} \+</code></pre>
+<p>Entonces elimina el directorio <emb>$PKG</emb>, por si hubiera una compilación anterior fallida o lo que fuera. Después, crea -si no existen- los directorios de trabajo previamente definidos. Nos movemos a <emb>/tmp/SBo</emb>, borra cualquier directorio que pudiera haber de código fuente, extrae con <emb>tar xvf</emb> el tarball que debe estar en la misma carpeta que el SlackBuild (<emb>$CWD</emb>) y accedemos a la carpeta del código fuente.</p>
+<p>Entonces, aplicamos una "reparación de permisos", que inicia cambiando el propietario recursivamente a <emb>root:root</emb> y, mediante el comando <emb>find</emb>, buscamos archivos y carpetas con permisos inusuales, o demasiado permisivos. Los ejecutables o directorios se pondrán en permiso 755 (<emb>rwxr-xr-x</emb>), el resto de archivos en 644 (<emb>rw-r--r--</emb>).</p>
+<p>Después, con <emb>CFLAGS="$SLKCFLAGS $(getconf LFS_CFLAGS)" make</emb> definimos variables de entorno para el comando <emb>make</emb>, utilizando los parámetros del inicio y ejecutando <emb>getconf</emb> para obtener otros parámetros necesarios.</p>
+<pre><code>case "$(ps -o stat= -p $$)" in
+ *+*) make check ;; # running in foreground
+ *) echo '*** Not running "make check" because we are in the background.' ;;
+esac</code></pre>
+<p>Es entonces cuando iniciamos la fase de compilación. En términos generales se realiza directament el <emb>make</emb>, pero se ve que el programador de este paquete de ejemplo le añadió algo de complejidad: a veces, parece qu eel paquete en instalación (<emb>ksh-openbsd</emb>, recuerdo) se cuelga durante el <emb>make check</emb>, que indica una fase de testing, cuando se ejecuta en segundo plano. Esto ocurre con más frecuencia cuando se usa <emb>sbopkg</emb>, <emb>queue</emb> o scripts de compilación masiva. El test se quedaría esperando algo de terminal/entrada y bloquea toda la cola. ¿La solución? sencilla: si estoy ejecutando el SlackBuild manualmente en una términal, haga los test; si no, ignórelos.</p>
+<p>Entonces, sí hacemos el make con <emb>make install DESTDIR=$PKG</emb> sobre el directorio de trabajo final.</p>
+<pre><code>if [ -n "${PDKSH_BINNAME}" ];then
+ mv $PKG/bin/pdksh $PKG/bin/"${PDKSH_BINNAME}"
+ mv $PKG/usr/man/man1/pdksh.1 $PKG/usr/man/man1/"${PDKSH_BINNAME}".1
+ mv $PKG/usr/man/man1/pdksh-sh.1 $PKG/usr/man/man1/"${PDKSH_BINNAME}"-sh.1
+fi
+BINNAME=${PDKSH_BINNAME:-pdksh}</code></pre>
+<p>Si el usuario define la variable de entorno <emb>PDKSH_BINNAME</emb> antes de ejecutar el script, entonces renombra todo para que el shell no se llame <emb>pdksh</emb>. Por ejemplo, si el usuario ha ejecutado antes <emb>PDKSH_BINNAME=ksh ./ksh-openbsd.SlackBuild</emb>, el binario pasaría a llamarse <emb>ksh</emb> en lugar de <emb>pdksh</emb> (renombrando a su vez las páginas de manual correspondientes, claro está).</p>
+<pre><code>strip --strip-unneeded $PKG/bin/"${BINNAME}"
+gzip -9 $PKG/usr/man/man1/"${BINNAME}".1
+gzip -9 $PKG/usr/man/man1/"${BINNAME}"-sh.1</code></pre>
+<p>El comando <emb>strip</emb> sobre el binario principal elimina todos los símbolos de depuración y sesiones innecesarias del ejecutable, pero sin romper las funciones necesarias (de ahí que se use <emb>--strip-unneeded</emb> en lugar de <emb>--strip-all</emb>). Esto reduce considerablemente el tamaño del binario final. Es una práctica estándar en todos los paquetes de Slackware.</p>
+<p>Después, comprime las páginas de manual con <emb>gzip</emb> usando el nivel máximo de compresión (<emb>-9</emb>).</p>
+<pre><code>mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
+cp -a \
+ Changelog.ksh-openbsd LEGAL README \
+ $PKG/usr/doc/$PRGNAM-$VERSION
+cp $CWD/README $PKG/usr/doc/$PRGNAM-$VERSION/README.ksh-openbsd
+cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
+
+mkdir -p $PKG/install</code></pre>
+<p>Y finalmente, creamos el directorio con la documentación, copiamos ésta y, encima, copiamos el propio SlackBuild dentro de dicha carpeta. Esto está encarecidamente recomendado por las buenas prácticas de un SlackBuild, puesto que permite al usuario final ver cómo se compiló el paquete en cualquier momento. Es útil además para depuraciónh y para reproducción, en caso necesario.</p>
+<p>Además, crea el directorio <emb>/install</emb> dentro del propio paquete. Aquí almacenará los archivos de metadatos del paquete, como <emb>slack-desc</emb>, <emb>doinst.sh</emb>, <emb>slack-required</emb>, <emb>slack-conflicts</emb>, etcétera.</p>
+<p>Como hemos visto, el contenido de un SlackBuild es muy completo, contando con todas las fases de despliegue de un software: preparación, parametrización, configuración de compilación o pre-compilación, extracción y limpieza, compilación, instalación, optimización, documentación, empaquetado final... Se trata de un guión y hoja de ruta poderosa para el usuario de Slackware, desde luego, y muy útil y práctica en el día a día de la administración de este sistema.</p>
+</body>
+</html>
diff --git a/slackware/index.html b/slackware/index.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>De Slackware</title>
+<link rel="icon" type="image/png" href="/favicon.png" />
+<link rel="stylesheet" type="text/css" href="../article.css" />
+</head>
+<body>
+<header>
+<p class="title">De Slackware</p>
+<p class="date">16 de marzo de 2024 • fjbalon</p>
+</header>
+<p>Slackware es la distribución de Linux más vieja y antigua que aún se mantiene con vida. Su lanzamiento inicial fue en 1993 y fue fundada por Patrick Volkerding, basándose en su momento en la distribución SLS Linux, de Peter MacDonald (1992), mismo padre que llevó a Ian Murdock a hacer Debian tan solo unos meses después. De hecho, en 1994, las dos distribuciones de Linux más importantes eran Debian y Slackware, ni más ni menos.</p>
+<p>Slackware tiene una filosofía muy rancia, siendo prácticamente más cercano a la filosofía Unix que a GNU/Linux en sí; hoy en día es aún más acusada la diferencia, <b>siendo mucho más cercano a FreeBSD original que a una distribución moderna de Linux</b>, como Ubuntu o Fedora.</p>
+<p>Slack significa perezoso en inglés, ya que la mayor parte de la configuración del sistema depende del usuario. También resulta que Patrick Volkerding pertenecía -o sentía simpatía, no lo sé- a la «Iglesia de los subgenios» (una parodia de religión satírica postmoderna americana), donde el término Slack hace referencia a algo así como "libertad de pensamiento". Según la Wikipedia, los subgenios se autodefinen como una orden de herejes y blasfemos dedicados al Slack (?).</p>
+<p>De entre las características que más destaco de esta noble distribución, y que la hacen <b>aristocracia</b> distributiva, diría:</p>
+<ol>
+<li>El <b>mantenimiento radical de la filosofía KISS</b> (<i>Keep It Simple Stupid!</i>), de sobra conocida por los usuarios con pretensiones más avanzadas, pero que en este caso se acentúa con la radical adopción de la filosofía de Unix. Uno de los principios de Slackware es mantener <b>ausencia total de interfaz gráfica para nada relacionado con la instalación, configuración y mantenimiento del sistema</b>. El usuario deberá instalar las herramientas gráficas de terceros que desee, pero eso le compete a él y no a la distribución.</li>
+<li>Un robusto <b>enfoque en la estabilidad</b>. Tanto es así que se nota en su enfoque a largo plazo: actualmente está vigente la versión 15 -desde 2022-, mientras que su versión 14 se lanzó en 2012; una década de diferencia entre dos versiones estables.</li>
+<li>La instalación del sistema operativo, como Archlinux u otras, se hace <b>mediante línea de comandos</b>; si bien sí es cierto que ofrece un script que automatiza gran parte de estos procesos mediante dialog ó Ncurses, haciendo la instalación más sencilla.</li>
+<li>No utiliza systemd, por supuesto. <b>Slackware utiliza scripts de init de tipo BSD</b>, mientras que la mayoría de distribuciones usaba entonces el estilo de scripts de System V (ahora conquistados por systemd). Los fieles al estilo BSD defienden que es mejor con este sistema con el que se hace más fácil encontrar, leer, editar y mantener los scripts de inicio. Yo estoy de acuerdo.</li>
+</ol>
+<p>Es una distribución dura, no os quiero mentir. Slackware no te toma por idiota, menos aún por profano o hereje. Por ello, suele ser un escollo para muchos distrohoppers que se topan con ella. Su tradicionalismo rancio y su inflexibilidad lo hacen áspero, rígido y férreo para digerirlo por parte de usuarios no preparados. Desde luego en ello no veo sino su mejor ventaja.</p>
+<p>Y deliberadamente, he querido dejar para el final el último punto de la lista, que es el que más resquemor y acidez producen en los incautos que se aventuran en Slackware sin estar suficientemente iniciados: la administración de paquetes:</p>
+<ol start="5">
+<li>La administración de paquetes, que incluye el manejo de paquetes, repositorios y dependencias es una característica muy identificativa de Slackware. Y es que, para empezar, no usa los típicos paquetes DEB ni RPM, sino usa directamente <b>tarballs</b>. O sea, archivos <b>empaquetados y comprimidos con .tar.gz</b> -generalmente-. <p>Además, el sistema <b>carece de sistema automatizado y transparente al usuario para rastrear o manejar dependencias</b>, teniendo que ser resueltas manualmente por el propio usuario. A menudo se vuelve tedioso, sobretodo con programas muy vitaminados o softwares muy grandes.</p>
+<p>Esto produce, a menudo, que el usuario tenga que hacerse prácticamente un esquema con el árbol de dependencias a instalar antes de poder instalar el paquete que necesitas. Al principio es algo frustrante, lo admito. Si bien al final entiendes el potencial que subyace y el verdadero gran dominio de todo el software que corre en tu sistema que te da Slackware. Sobretodo cuando venimos de la costumbre del empleo de gestores de paquetes bastante generalistas y que centralizan y automatizan gran parte del trabajo, como Pacman, APT, DNF o YUM</p>
+<p>No obstante, Slackware cuenta con software de administración de paquetes:</p>
+<ol type="a">
+<li>pkgtools es el gestor de paquetes estándar y predeterminado. Incluye herramientas como installpkg, removepkg, upgradepkg, etc. Tiene un uso parecido y típico al que estamos acostumbrados. Es extremadamente simple de usar y muy eficiente, sin embargo no tienen muchas características que consideraríamos avanzadas, como la resolución automática de dependencias, lo que aveces constituye un hueso. <p>Como sorpresa bastante interesante, existe un script denominado rpm2tgz que te permite transformar los paquetes clásicos de RPM en instalable sencillo para Slackware, de tal forma que el resultado .tgz puede ser pasado como argumento a installpkg. Muy útil.</p></li>
+<li>slackpkg es la herramienta de gestión de paquetes más parecida a APT o DNF, permitiéndote buscar, instalar, actualizar y eliminar paquetes de los repositorios oficiales de Slackware. También puede manejar actualizaciones de seguridad y parches del sistema.</li>
+<li>sbopkg es un gestor de paquetes para <a href="https://slackbuilds.org/">Slackbuilds.org</a>, que es un repositorio de software fuera del reducido catálogo de Slackware. Diría que es el equivalente a AUR en Archlinux. sbopkg ofrece un conjunto de herramientas de terminal y de dialog que automatizan la compilación e instalación de software. Te permite buscar, descargar, compilar e instalar paquetes slackbuilds.</li>
+</ol>
+</p>
+</li>
+</ol>
+<p>Evidentemente, que a pesar de su rito iniciático, su rigidez, su tradicionalismo y su misticismo, Slackware puede ser utilizado y dominado como cualquier otra distribución de GNU/Linux, se puede instalar el mismo software y se puede conducir de la misma forma. Pero exije, exije al usuario paciencia y sacrificio.</p>
+<p>En un foro especializado en Linux me preguntaron si sigue siendo viable utilizar Slackware hoy día, la respuesta es evidente: claro que sí. Y depende más bien de qué tan dispuesto estés a tomar el control de tu sistema con una forma heredada más tipo Unix (véase <a href="../unix-filosofia/"><i>Unix es Tradición</i></a>). Desde mi atalaya -construida sobre Slackware, claro- no puedo sino recomendar, a los fuertes y los valientes, iniciarse en el sistema más antiguo.</p>
+</body>
+</html>
+\ No newline at end of file
diff --git a/sparse-files/index.html b/sparse-files/index.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Sparse files</title>
+<link rel="icon" type="image/png" href="/favicon.png" />
+<link rel="stylesheet" type="text/css" href="../article.css" />
+</head>
+<body>
+<header>
+<p class="title">Dispersión de archivos (sparse files) como método eficiente de uso del espacio</p>
+<p class="date">20 de mayo de 2023 • fjbalon</p>
+</header>
+<p>En informática, un archivo disperso es un tipo que utiliza más eficientemente el espacio del sistema de archivos cuando los bloques asignados a los archivos están en su mayor parte vacíos. Esto se consigue escribiendo breves metadatos que representan los bloques vacíos en el disco en vez del verdadero espacio 'vacío' que constituye dicho bloque, y utilizando así menos espacio en disco.</p>
+<p>Cuando trabajamos clonando discos, a menudo nos surgen problemas de espacio en disco local, debido a que trabajamos con -normalmente- muchos gigabytes, e incluso terabytes hoy día. Los algoritmos de compresión nos ayudan a reducir considerablemente el uso que estas imágenes tienen del disco, permitiendo almacenar un número considerable. Sin embargo, existen ocasiones en las que requerimos trabajar con los discos sin compresión en local, por ejemplo, cuando necesitamos montar uno de ellos y trabajar sobre él. Para ello, la mejor técnica es emplear los conocidos «sparse files», que son un tipo de fichero con un tamaño específico, pero que no reserva dicho espacio en el sistema de ficheros.</p>
+<img class="color-invertible" src="resources/schema.png" />
+<p>dd permite guardar espacio con este tipo de ficheros usando el parámetro <emb>conv=sparse</emb>. Sin embargo, puede no ser tan optimizado debido al búfer utilizado (<emb>sparse try to seek rather than write the output for NUL input blocks</emb>). Por lo que si utilizamos un tamaño de bloque obs elevado, tendremos poca optimización. Para obviar este problema, podemos emplear directamente cp sobre el archivo comprimido:</p>
+<pre><code>gunzip -c /image.img.gz | cp --sparse=always /dev/stdin mini.img</code></pre>
+<p>O bien directamente sobre el disco obviando el uso de dd:</p>
+<pre><code>cp --sparse=always /dev/sdx mini.img</code></pre>
+<p>De tal forma que observamos una optimización general en función de los bits ocupados en disco, y teniendo como resultado una imagen completa sin apenas utilización de disco:</p>
+<pre><code>ls -hls
+
+4,8G -rw-r--r-- 1 balon users 477G ene 17 10:03 mini.img
+2,3G -rw-r--r-- 1 balon users 2,3G ene 13 12:26 sdd.img.gz</code></pre>
+<p>Si se quiere profundizar más en el tema puede ser de verdadera utilidad:</p>
+<ul>
+<li><a href="https://en.wikipedia.org/wiki/Dd_(Unix)">dd - Wikipedia</a> / <a href="https://wiki.archlinux.org/title/Dd">dd - Archlinux Wiki</a></li>
+<li><a href="http://blog.tdg5.com/tuning-dd-block-size/">Tuning dd block size</a>, tdg5</li>
+<li><a href="https://unix.stackexchange.com/questions/731487/mount-compressed-disk-image-or-clone-with-dd-respecting-free-space">Mount compressed disk image or clone with dd respecting free space</a>, Unix&Linux (Stack Exchange)</li>
+<li><a href="https://superuser.com/questions/1136357/why-didnt-dd-conv-sparse-save-space-as-i-expected">Why didn't `dd conv=sparse` save space as I expected?</a>, SuperUser (Stack Exchange)</li>
+<li><a href="https://superuser.com/questions/622541/what-does-dd-conv-sync-noerror-do/1075837#1075837">What does dd conv=sync,noerror do?</a>, SuperUser (Stack Exchange)</li>
+</ul>
+</body>
+</html>
+\ No newline at end of file
diff --git a/sparse-files/resources/schema.png b/sparse-files/resources/schema.png
Binary files differ.
diff --git a/ssh-tunneling/index.html b/ssh-tunneling/index.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>SSH Tunneling</title>
+<link rel="icon" type="image/png" href="/favicon.png" />
+<link rel="stylesheet" type="text/css" href="../article.css" />
+</head>
+<body>
+<header>
+<p class="title">SSH Tunneling</p>
+<p class="date">28 de marzo de 2019 • fjbalon</p>
+</header>
+<p>El tunneling es un proceso por el que se utiliza el protocolo SSH para fortificar la comunicación entre otros protocolos inseguros, por ejemplo para realizar peticiones HTTP, SMTP, etc.</p>
+<p>Los túneles pueden ser locales o remotos. En los túneles locales, la máquina del administrador o cliente redirecciona un puerto local hacia un puerto de la máquina remota, a la que se disponga de acceso. En los túneles remotos se redirecciona un puerto remoto dela máquina remota, a la que se disponga de aacceso, a un puerto de la máquina local, donde se encuentra el administrador.</p>
+<p>La sintaxis para la creación de un túnel local hacia el puerto remoto de la máquina remota es la siguiente:</p>
+<pre><code>ssh -L [direccion de escucha:]puerto escucha:maquina remota: puerto remoto usuario@server</code></pre>
+<img class="color-invertible" src="resources/ssh01.png"/>
+<p>El escenario idóneo para la utilización de túneles SSH locales es el siguiente:</p>
+<ul>
+<li>Máquina A con conexión a Internet requiere conexión a máquina C, que se encuentra detrás de un servidor que impide el paso. En otras palabras, la máquina C no es accesible desde Internet.</li>
+<li>El usuarioo de la máquina A dispone de cuenta en una máquina B. La máquina B es el servidor que proporciona la salida a Internet a la máquina C. La máquina A creará un túnel con la máquina B y a través del forwarding (véase sección \ref{sshforwarding} para más detalle) de la máquina B llegará a la máquina C.</li>
+<li>Lo importante es proteger la comunicación en Internet entre la máquina A y B. La comunicación entre B y C puede ir sin cifrar, ya que se encentra en una Intranet. Aunque también puede ser altamente recomendable fortificar dicha comunicación.</li>
+</ul>
+<p>El túnel remoto, por su lado, generará un socket a la escucha en un servidor, el cual al recibir una petición reenviará el tráfico mediante SSH a la máquina local donde se encuentre el administrador. La sintaxis es:</p>
+<pre><code>ssh -R puerto local:maquina remota:puerto remoto</code></pre>
+<img class="color-invertible" src="resources/ssh02.png"/>
+<p>Un ejemplo sería querer que una máquina en Internet llegase al interior de la Intranet a través de una máquina puente de la propia red privada, manteniendo una interfaz hacia Internet. El escenario sería el siguiente:</p>
+<ul>
+<li>Máquina A, la máquina se encuentra en una red interna.</li>
+<li>Máquina B, máquina con conectividad con A e interfaz en Internet.</li>
+<li>Máquina C, máquina externa con conectividad con B, pero no con A.</li>
+</ul>
+<p>Estas técnicas cuentan con una serie de escenarios muy interesantes, siendo los más usuales:</p>
+<ol>
+<li>Usar un túnel externo para atravesar el firewall y acceder a un recurso que ofrece un equipo de la intranet.</li>
+<li>Usar un túnel externo para atravesar el firewall y acceder a un recurso de una intranet. Pero además cualquier equipo puede conectarse a dicho equipo de la intranet a través de una conexión con el equipo externo.</li>
+<li>Usar un túnel interno para que los equipos de fuera de la red se conecten al interior. Esta acción se realizará mediante túneles remotos.</li>
+<li>Túnel interno para que equipos de fuera de la red se conecten al interior, pero además que otros equipos del exterior puedan conectarse a través del externo remoto.</li>
+<li>Utilizar un túnel para que desde una máquina externa se pueda atravesar el firewall y realizar el forwarding en una máquina interna, y que esta reenvíe el tráfico a la segunda máquina interna.</li>
+</ol>
+<pre><code>ssh -L 7900:localhost:5900 usuario@internal #1
+ssh -L 0.0.0.0:7900:localhost:5900 usuario@internal #2
+ssh -R 7900:localhost:5900 usuario@internal #3
+ssh -R 0.0.0.0:7900:localhost:5900 usuario@internal #4
+ssh -L 7900:internal2:5900 usuario@internal #5</code></pre>
+</body>
+</html>
+\ No newline at end of file
diff --git a/ssh-tunneling/resources/ssh01.png b/ssh-tunneling/resources/ssh01.png
Binary files differ.
diff --git a/ssh-tunneling/resources/ssh02.png b/ssh-tunneling/resources/ssh02.png
Binary files differ.
diff --git a/ssh/index.html b/ssh/index.html
@@ -0,0 +1,258 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Robustecimiento y securización del protocolo SSH</title>
+<link rel="icon" type="image/png" href="/favicon.png" />
+<link rel="stylesheet" type="text/css" href="../article.css" />
+</head>
+<body>
+<header>
+<p class="title">Robustecimiento y securización del protocolo SSH</p>
+<p class="date">20 de febrero de 2019 • fjbalon</p>
+</header>
+<p>SSH es uno de los protocolos más interesantes de los que dispone el administrador de sistemas, permitiendo acceder a otros equipos de forma remota; pero sobretodo, de forma segura. Con SSH creamos un túnel entre cliente y servidor que simula, en la capa de aplicación, la shell o intérprete de comandos del servidor, dotando al administrador de toda funcionalidad en el equipo.</p>
+<p>SSH puede considerarse una evolución del protocolo Telnet, pero el primero cuenta con técnicas de criptografía para proteger los datos intercambiados entre ambos nodos que conforman la conexión SSH. SSH utiliza un intercambio de claves basado en el protocolo criptográfico de Diffie-Hellman, imprescindible en el robustecimiento de la capa de transporte.</p>
+<p>SSH trabaja sobre el protocolo TCP/IP. Por ello, en primer lugar se realiza la conexión TCP, realizando el three-way handshake. Después de abrir la conexión, cliente y servidor se envían la versión disponible del protocolo. Se utilizará luego el par de claves, pública y privada, de RSA. El servidor enviará su clave pública de host al cliente, de forma que éste pueda cifrar lo que necesite enviar al servidor. El cliente comparará la clave pública de host con la que tenga almacenada en el archivo known_hosts, si lo hubiera.</p>
+<p>Una vez el cliente dispone de la clave pública del host del servidor, este generará una clave de sesión aleatoria y seleccionará un algoritmo de cifrado simétrico. Con esta clave de sesión, que se generará por defecto cada 3600 segundos, se cifrará el túnel. El cliente enviará un mensaje que contiene la clave de sesión y el algoritmo de cifrado seleccionado, información que viajará cifrada mediante la clave pública de host, al servidor. En este instante, el resto de la comunicación se utilizará el algoritmo de cifrado simétrico y la clave compartida de sesión, dando velocidad a la conexión (en técnicas de clave simétrica el cifrado y descifrado se hace más rápido), pero utilizando siempre primero el protocolo de Diffie-Hellman para poder enviar de forma segura la clave compartida de sesión; y supliendo así la principal carencia en seguridad de los algoritmos de criptografía simétrica: el intercambio de claves.</p>
+<p>Con el túnel creado, se llevará a cabo la autenticación del usuario en el servidor, pudiendo utilizar distintos métodos para llevar a cabo tal autenticación.</p>
+<img src="resources/ssh00.png" style="width: 70%;"/>
+
+ <h1>Autenticación mediante par de claves</h1>
+<p>una conexión común usando el protocolo SSH es de por sí segura; al menos más segura que una conexión no cifrada como telnet, pero presenta, grosso modo dos inconvenientes:</p>
+<ul>
+<li>La contraseña, aún yendo cifrada, viaja por la red siempre que nos autenticamos. Esto puede ser peligroso en el caso que haya alguien sniffeando el tráfico de nuestra red y fuese capaz de descifrar nuestra clave (mediante ataques por fuerza bruta o diccionario, utilizando alguna vulnerabilidad conocida, etc.).</li>
+<li>En el caso de manejar numerosos servidores y conexiones SSH puede ser muy tedioso tener que estar recordando contraseñas, almacenandolas, etc. Este método agregaría un plus de comodidad y escalabilidad a las conexiones.</li>
+</ul>
+
+ La implementación del algoritmo RSA presenta solución a estos problemas. Su funcionamiento es:
+<ol>
+<li>El cliente envía información sobre su clave pública al servidor.</li>
+<li>El servidor busca en su base de datos la clave pública del cliente y, cuando la encuentra, envía al cliente un challenge (desafío), que contiene un número aleatorio generado y cifrado por éste utilizando la clave pública del cliente.</li>
+<li>El cliente recibe el paquete cifrado y usa su clave privada para descifrarlo y devolvérselo al servidor.</li>
+<li>El servidor comprueba que el número devuelto es el que mandó cifrado, en caso afirmativo, el usuario se ha autenticado y se le permite la sesión de shell.</li>
+</ol>
+<p>En ningún momento se envían claves por Internet (más que el envío de la clave pública al servidor en el primer contacto, para que éste la conozca). Por supuesto si alguien accede a nuestro equipo y nos roba la clave privada podría autenticarse como nosotros y suplantar nuestra identidad criptográfica. Por esta razón es necesario proteger las distintas formas de acceso, desde cifrado de particiones a configuración estricta de permisos.</p>
+<p>También es posible asignar un cifrado simétrico sobre las claves asimétricas, dando una capa extra de seguridad a cambio de tener que introducir una clave cada vez que la usemos.</p>
+<p>La configuración del servidor oldscizor es sencilla:</p>
+
+<pre><code># /etc/ssh/sshd_config
+RSAAuthentication yes
+PubkeyAuthentication yes
+AuthorizedKeysFile %h/.ssh/authorized_keys</code></pre>
+<p>Véase la última línea, donde añadimos el fichero que almacenará las claves públicas de los clientes reconocidos. Si no existiera este directorio y/o fichero deberemos crearlo.</p>
+<p>Por otro lado, la configuración del cliente scizor consiste en la generación del par de claves RSA para éste:</p>
+
+<pre><code>$ ssh-keygen -t rsa
+Generating public/private rsa key pair.
+Enter file in which to save the key (/home/scizor/.ssh/id_rsa):
+/home/scizor/.ssh/rsa
+Enter passphrase (empty for no passphrase):
+Enter same passphrase again:
+Your identification has been saved in /home/scizor/.ssh/rsa
+Your public key has been saved in /home/scizor/.ssh/rsa.pub
+The key fingerprint is:
+SHA256:aVgQfYrakZnFhaw4Gcl0bHqrJj7QtR3dXm332wx9qdE scizor@client
+The key's randomart image is:
++---[RSA 3072]----+
+| o.o+= o. |
+| +.o.* . |
+| * O.+ . |
+| * Xoo.. . o .|
+| . . B.+S. . ..oo|
+|. . o +. . ..E+|
+| . . oo+|
+| o o . .o|
+| ..+ |
++----[SHA256]-----+</code></pre>
+<p>A continuación debemos configurar el ssh-agent para añadirle nuestra clave privada emparejada con la pública que enviaremos al servidor, de forma que, ejecutándose junto a la sesión, éste esté vinculado a ella directamente.</p>
+
+<pre><code>$ eval $(ssh-agent -s)
+Agent pid 15081
+$ ssh-add ~/.ssh/rsa
+Identity added: /home/scizor/.ssh/rsa
+(/home/scizor/.ssh/rsa)</code></pre>
+
+ Otra opción es utilizar el fichero config:
+
+<pre><code># ~/.ssh/config
+Host oldscizor.es
+ User scizor
+ IdentityFile ~/.ssh/server_key</code></pre>
+<p>La clave pública deberá ser enviada al servidor y almacenada en authorized_keys o en el fichero seleccionado.</p>
+
+<pre><code># cat ~/.ssh/authorized_keys
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCoaiQqlc0hhqdVsh52sB/ui
+ISb1pRU/6DVWqyvpCYWQOd8PGNGjuFwYeOnTQ1mZYppuNoXmQxzKXJXGK4ke/
+4HcgRHj9l2zZL0LBacnU1NEszqVYUgpI4+1qbyMi0LQZTpKedGULFcSVa1QDt
+SWTLeQIYTK7dphN4wo7cer9EFkfj5Z1ZNWSjC4blTFTGD2L03aSUklek+BHkk
+FFGYmVKw/+VD7aOA+Imsb/qHp1eUhEKcHSlWPfDS6qf+GwJoB72v4TMCH1At1
+fM2LP8o/eRF31fZdRJGOHL+MzfXR0RqS1SLfr/1g6NRohmu1BFFdQQxisovPf
+h1iOBs4apqQjRl6P6qQziwSVShkkzDW0xOnIflWwbYjo/w1SFN5YzwDaOV3QK
+VYEeHQGm2mdwPGqPxyeyTaCZqf5Ca2k/Gv53BlRCUb3ATpXTbN6HzIliOUtFm
+idUAYQwYM0n7VMpL7NW+/1ap6UthX/ep/CjcxGqYZc4+iTSSSict9caCSGSY+
+Ec= scizor@client</code></pre>
+<p>Finalizada la configuración, observamos el proceso de conexión mediante el parámetro verbose:</p>
+
+<pre><code>$ ssh -v oldscizor.es
+OpenSSH_8.8p1, OpenSSL 1.1.1l 24 Aug 2021
+debug1: Reading configuration data /home/scizor/.ssh/config
+debug1: /home/scizor/.ssh/config line 9: Applying options for oldscizor.es
+debug1: /home/scizor/.ssh/config line 13: Applying options for oldscizor.es
+debug1: Reading configuration data /etc/ssh/ssh_config
+debug1: Connecting to oldscizor.es [54.38.52.183] port 22.
+debug1: Connection established.
+debug1: identity file /home/scizor/.ssh/oldscizor type 0
+debug1: identity file /home/scizor/.ssh/oldscizor-cert type -1
+debug1: identity file /home/scizor/.ssh/scizorc type 0
+debug1: identity file /home/scizor/.ssh/scizorc-cert type -1
+debug1: Local version string SSH-2.0-OpenSSH_8.8
+debug1: Remote protocol version 2.0, remote software version OpenSSH_7.9p1 Debian-10+deb10u2
+debug1: compat_banner: match: OpenSSH_7.9p1 Debian-10+deb10u2 pat OpenSSH* compat 0x04000000
+debug1: Authenticating to oldscizor.es:22 as 'scizor'
+debug1: load_hostkeys: fopen /home/scizor/.ssh/known_hosts2: No such file or directory
+debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory
+debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory
+debug1: SSH2_MSG_KEXINIT sent
+debug1: SSH2_MSG_KEXINIT received
+debug1: kex: algorithm: curve25519-sha256
+debug1: kex: host key algorithm: ssh-ed25519
+debug1: kex: server->client cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none
+debug1: kex: client->server cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none
+debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
+debug1: SSH2_MSG_KEX_ECDH_REPLY received
+debug1: Server host key: ssh-ed25519 SHA256:d6TuEWkCHpZXztBeSP2s2dVCRC+nHu3a2JxnJXioA34
+debug1: load_hostkeys: fopen /home/scizor/.ssh/known_hosts2: No such file or directory
+debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory
+debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory
+debug1: Host 'oldscizor.es' is known and matches the ED25519 host key.
+debug1: Found key in /home/scizor/.ssh/known_hosts:7
+debug1: rekey out after 134217728 blocks
+debug1: SSH2_MSG_NEWKEYS sent
+debug1: expecting SSH2_MSG_NEWKEYS
+debug1: SSH2_MSG_NEWKEYS received
+debug1: rekey in after 134217728 blocks
+debug1: Will attempt key: /home/scizor/.ssh/oldscizor RSA SHA256:zFOQBJRsUuKhgVyvCkKaJDcJ/Y7qWq2VEN1lRkJxL74 explicit
+debug1: Will attempt key: /home/scizor/.ssh/scizorc RSA SHA256:0zdBByBWUvwkcfgcRYL68IdoNMOmJwijG2QiHsgcTaM explicit
+debug1: SSH2_MSG_EXT_INFO received
+debug1: kex_input_ext_info: server-sig-algs=<ssh-ed25519,ssh-rsa,rsa-sha2-256,rsa-sha2-512,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521>
+debug1: SSH2_MSG_SERVICE_ACCEPT received
+debug1: Authentications that can continue: publickey
+debug1: Next authentication method: publickey
+debug1: Offering public key: /home/scizor/.ssh/oldscizor RSA SHA256:zFOQBJRsUuKhgVyvCkKaJDcJ/Y7qWq2VEN1lRkJxL74 explicit
+debug1: Server accepts key: /home/scizor/.ssh/oldscizor RSA SHA256:zFOQBJRsUuKhgVyvCkKaJDcJ/Y7qWq2VEN1lRkJxL74 explicit
+Authenticated to oldscizor.es ([54.38.52.183]:22) using "publickey".
+debug1: channel 0: new [client-session]
+debug1: Requesting no-more-sessions@openssh.com
+debug1: Entering interactive session.
+debug1: pledge: filesystem full
+debug1: client_input_global_request: rtype hostkeys-00@openssh.com want_reply 0
+debug1: client_input_hostkeys: searching /home/scizor/.ssh/known_hosts for oldscizor.es / (none)
+debug1: client_input_hostkeys: searching /home/scizor/.ssh/known_hosts2 for oldscizor.es / (none)
+debug1: client_input_hostkeys: hostkeys file /home/scizor/.ssh/known_hosts2 does not exist
+debug1: client_input_hostkeys: no new or deprecated keys from server
+debug1: Remote: /home/scizor/.ssh/authorized_keys:1: key options: agent-forwarding port-forwarding pty user-rc x11-forwarding
+debug1: Remote: /home/scizor/.ssh/authorized_keys:1: key options: agent-forwarding port-forwarding pty user-rc x11-forwarding
+Linux oldscizor 4.19.0-17-cloud-amd64 #1 SMP Debian 4.19.194-3 (2021-07-18) x86_64
+
+The programs included with the Debian GNU/Linux system are free software;
+the exact distribution terms for each program are described in the
+individual files in /usr/share/doc/*/copyright.
+
+Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
+permitted by applicable law.
+Last login: Tue Nov 16 21:56:22 2021 from 172.16.7.12
+scizor@oldscizor:~$</code></pre>
+<p>El cliente lee el fichero ssh_config antes de realizar la conexión al servidor oldscizor.es en su puerto por defecto 22. Tras esto, se crea la conexión TCP y, una vez se realiza el three-way handshake entre cliente y servidor, la conexión queda establecida; pero aún no existe canal cifrado.</p>
+<p>El cliente verifica la existencia de posibles claves privadas y verifica si se encuentra alguna en la lista negra. Una vez realizado este proceso, verifica también la versión del protocolo. Es en este instante en el que se intercambian la clave pública host del servidor al cliente, para que éste pueda generar y cifrar la clave simétrica, la cual será la encargada de cifrar el canal.</p>
+<p>Una vez el cliente recibe la clave del host, la verifica en el fichero known_hosts. Si se encuentra, se verifica la identidad del servidor. Si por el contrario no se encuentra mostraría un mensaje avisando de la posible suplantación (por defecto).</p>
+<p>Tras aceptar el cliente al servidor, verificando la identidad de éste, se establece la conexión en un canal ya seguro. El servidor envía el banner y el cliente lo muestra por pantalla. Despues, el servidor envía al cliente los métodos de autenticación para el usuario de los que se disponen y el cliente valorará su configuración previamente cargada para realizar la autenticación pertinente; que en nuestro ejercicio es una autenticación basada en claves RSA, y tras autenticarse, se envían desde el servidor las variables de entorno de la sesión y proporciona el control de la shell en remoto.</p>
+
+ <h1>Aplicaciones del protocolo SSH</h1>
+<p>Sobre SSH existen varias aplicaciones que sirven de arsenal bastante completo al administrador de sistemas. Enumero las que conozco:</p>
+<h2>Automatización envío de claves públicas RSA</h2>
+<p>La utilidad ssh-copy-id permite enviar las claves públicas directamente a tantos servidores sea necesario, automatizando y simplificando la comunicación cifrada contra múltiples equipos sin necesidad de abrir una sesión en cada uno de ellos.</p>
+
+<pre><code> .---------------------------------------.
+ | aws:/home/thufir/.ssh/authorized_keys |
+ |---------------------------------------|
+ | ssh-rsa AAAA... user10@host |
+ '---------------------------------------'
+ ^
+ |
+ |
+ ssh-copy-id | .---------------------------------------.
+ | | aws:/home/ubuntu/.ssh/authorized_keys |
+ .---' |---------------------------------------|
+ | | ssh-rsa AAAA... user10@host |
+ | '---------------------------------------'
+ | ^
+.---------------------------------------. |
+| local:/home/user10/.ssh/id_rsa | | ssh-copy-id
+| Private Key | |
+|---------------------------------------| |
+| BEGIN RSA PRIVATE KEY |----------.
+| Proc-Type: 4,ENCRYPTED | |
+| DEK-Info: AES- | | ssh-copy-id
+'---------------------------------------' |
+ | v
+ | .---------------------------------------.
+ '---. | aws2:/home/user5/.ssh/authorized_keys |
+ | |---------------------------------------|
+ | | ssh-rsa AAAA... user10@host |
+ ssh-copy-id | '---------------------------------------'
+ |
+ v
+ .----------------------------------------.
+ | aws2:/root/.ssh/authorized_keys |
+ |----------------------------------------|
+ | ssh-rsa AAAA... user10@host |
+ '----------------------------------------'</code></pre>
+<h2>Automatización de contraseñas con sshpass</h2>
+<p>Aunque no soy amigo de utilizar la autenticación básica por contraseña en mis infraestructuras SSH, a veces es necesario autenticar de esta forma, y nunca esta utilidad que permite al usuario cierta automatización a la hora de gestionar conexiones, principalmente cuando esta administración se hace desde otros programas o scripts donde no puede haber interactividad directa. La utilidad sshpass está diseñada para ejecutar SSH utilizando el modo de autenticación de contraseña interactiva de teclado, pero de una manera no interactiva, utilizando acceso TTY directo para garantizar que la contraseña sea emitida por un usuario de teclado interactivo, engañando a SSH haciéndole creer que está obteniendo la contraseña de un usuario interactivo.</p>
+<p>Su modo de uso es tan sencillo como indicar previamente a la comunicación con el servidor SSH la clave de éste tras el comando propio de sshpass:</p>
+
+<pre><code>$ sshpass -p !4u2tryhack ssh user@host</code></pre>
+<h2>SCP</h2>
+<p>SCP o Secure Copy es un protocolo similar funcionalmente a RCP (Remote Copy), cuyo objetivo es transferir archivos desde una máquina a otra. La diferencia entre ambos protocolos es que SCP utiliza el protocolo SSH para establecer sus comunicaciones, estableciendo un túnel cifrado por el que enviar dichos archivos.</p>
+<p>La ejecución de SCP es realmente sencilla, contando con la sintaxis:</p>
+
+<pre><code>$ scp [opciones] origen destino</code></pre>
+<p>Donde el origen o destino local es la ruta, ya sea absoluta o relativa y el origen o destino remoto cumple con su propia sintaxis:</p>
+
+<pre><code>usuario@host:<ruta_archivo></code></pre>
+<p>De tal forma que para enviar un archivo a un servidor mantendríamos la sintaxis:</p>
+<pre><code>$ scp /home/scizor/archivo oldscizor.es:/usr/archivo</code></pre>
+<p>Y siendo la forma inversa:</p>
+
+<pre><code>$ scp oldscizor:/usr/archivo2 /home/scizor/archivo2</code></pre>
+<p>Cabe destacar que también podemos realizar copias seguras entre máquinas remotas, no necesariamente debe ser una origen o destino local:</p>
+ <pre><code>$ scp oldscizor.es:/root/origen root@172.16.1.2:/etc/destino</code></pre>
+ <h2>SFTP</h2>
+<p>SSH File Transfer Protocol o SFTP permite el envío de ficheros a nivel de aplicación, a través de SSH, utilizando las aplicaciones y los comandos propios del protocolo FTP. Es sabido que el protocolo FTP no es seguro per se, debido a que no cuenta con cifrado.</p>
+<p>La sintaxis es similar al protocolo FTP, manteniendo una vez establecida la conexión una cadena de conexión a nivel de aplciación similar a SSH.</p>
+
+<pre><code>$ sftp oldscizor.es
+Connected to 10.101.5.3-
+sftp></code></pre>
+<h2>SSHFS</h2>
+<p>El protocolo SSH dispone de la posibilidad de gestionar el sistema de archivos de manera remota y segura utilizando SSHFS o Secure Shell File System. En el equipo local donde se realiza el montaje de SSHFS, la implementación hace uso del módulo del kérnel FUSE.</p>
+<p>La sintaxis es sencilla. Se debe ejecutar el comando sshfs seguido de la ruta remota que se quiere montar localmente y, por último, la ruta local que se utilizará como punto de montaje.</p>
+
+<pre><code>$ mkdir fs
+$ sshfs oldscizor.es:/home/git fs
+$ ls -l fs
+drwxr-xr-x 7 git git 4096 Nov 15 09:47 arch.git
+drwxr-xr-x 7 git git 4096 Oct 25 16:31 automata.git
+drwxr-xr-x 7 git git 4096 Nov 12 10:33 crypto.git
+drwxr-xr-x 7 git git 4096 Nov 12 10:22 dmenu.git
+drwxr-xr-x 7 git git 4096 Nov 15 09:32 dotfiles.git
+drwxr-xr-x 7 git git 4096 Nov 9 23:32 dwm.git</code></pre>
+<p>Una vez realizado el montaje, se puede utilizar cualquier tipo de operación como si la ruta fuera local. También podemos utilizar sobre el punto de montaje cualquier software, como un gestor de archivos gráfico para desempeñar el trabajo que sea. Todas las acciones remotas las hará de forma transparente al usuario y mediante un túnel cifrado.</p>
+<h2>X11 forwarding</h2>
+<p>Esta opción del protocolo SSH permite al usuario conectarse a un servidor para levantar procesos que requieran de un servidor gráfico para su interacción. De tal modo que un administrador pueda, por ejemplo, ejecutar un navegador en un servidor remoto, y la presentación gráfica se realizará en la máquina local a pesar del proceso encontrarse ejecutando en la máquina remota. Evidentemente, toda comunicación cliente-servidor se realizará de manera segura mediante el protocolo SSH, por lo que los datos de presentación del proceso viajarán por la red bajo este protocolo. Para poder redirigir la salida de las ventanas de los procesos que se ejecutan, el servidor debe habilitar la directiva X11Forwarding en su fichero sshd_config.</p>
+<p>Si bien el <a href="../ssh-tunneling/">SSH Tunneling</a> puede considerarse una aplicación del protocolo, he decidido hacer una entrada a parte sólo para ese caso, pues es más complejo y especial.</p>
+
+</body>
+</html>
+\ No newline at end of file
diff --git a/ssh/resources/ssh00.png b/ssh/resources/ssh00.png
Binary files differ.
diff --git a/ssh/resources/ssh01.png b/ssh/resources/ssh01.png
Binary files differ.
diff --git a/ssh/resources/ssh02.png b/ssh/resources/ssh02.png
Binary files differ.
diff --git a/swap/index.html b/swap/index.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Sobre la necesidad de la memoria Swap</title>
+<link rel="icon" type="image/png" href="/favicon.png" />
+<link rel="stylesheet" type="text/css" href="../article.css" />
+</head>
+<body>
+<header>
+<p class="title">Sobre la necesidad de la memoria Swap</p>
+<p class="date">27 de febrero de 2020 • fjbalon</p>
+</header>
+<p>El caso que hoy me ocupa, nace de la necesidad de apagar la memoria de intercambio (o swap) en mi equipo portátil para poder gestionar varias pruebas sobre clústers de kubernetes. Algo curioso, pues ningún programa me había obligado nunca a apagar la swap para funcionar (ya sé que puedo configurar kubernetes para evitar esta obligación, pero no se trata de un artículo sobre cómo evadir esta opción, sino de la memoria swap en sí). A raíz de este hecho, han avivado en mi memoria las viejas discusiones sobre la necesidad, o no, de la memoria de intercambio.</p>
+<p>Allá por el 2008, <a href="https://etbe.coker.com.au/2007/09/28/swap-space">Russell Coker discutía</a> sobre el uso de memoria swap que se daba en sistemas Unix, asegurando que la 'tradición' de utilizar el doble de swap que de RAM era obsoleto con las memorias de entonces (imagínese las actuales), llegando a la conclusión de que el tamaño más adecuado es el mismo que el tamaño de la memoria RAM siempre que ésta sea inferior a 1GB; la mitad del tamaño de la RAM cuando ésta tenga un tamaño de entre 2GB y 4GB; y 2GB de swap cuando el tamaño de la RAM sea mayor de 4GB. Coker además dudaría que exista ningún sistema de almacenamiento masivo que pueda manejar la carga de más de 2GB de espacio de intercambio en uso activo.</p>
+<p>¿Es necesaria la swap? La pregunta nace debido a que, por otro lado, hay quien defiende que hoy en día, con módulos de memoria baratos y de tal almacenamiento (tenga en cuenta que en mi equipo portátil tengo un almacenamiento de 32GB RAM), y debido al hecho de que el propio uso de memoria de intercambio supone una caída importante de rendimiento, la swap estaría obsoleta. También influye la idea de que, debe ser preferible tener suficiente RAM para evitar que llegue a sobrecargarse nunca y a necesitar espacio adicional, quedando éste relegado para máquinas con poca RAM o equipos antiguos.</p>
+<p>Al respecto, <a href="https://web.archive.org/web/20081022092522/http://sourcefrog.net/weblog/software/linux-kernel/swap.html">Martin Pool aseveraba en 2004</a>, que cuando el sistema empieza a quedarse sin memoria, el núcleo escogerá qué páginas pasan al disco, siendo normalmente las que se usan con menor frecuencia. Si una página escogida es 'no anónima' <sup>1</sup> siempre existe un archivo que sirve de respaldo al contenido de la página, por lo que puede ser recuperada fácilmente en el caso de que volvamos a necesitarla. Pero las páginas anónimas carecen de dicho respaldo, por lo que solo pueden ser salvadas y copiadas en la swap. Sin embargo, si no tenemos suficiente memoria, el memoria no podrá escoger páginas 'no anónimas' para liberarla, obligando al sistema a ganar memoria a costa de páginas 'no anónimas', aunque éstas estén siendo utilizadas en mayor medida que las anónimas, afectando al rendimiento del sistema. «Disk is cheap, so allocate a gigabyte or two for swap».</p>
+<p>Evidentemente, es necesario tener en cuenta, a parte del rendimiento, la seguridad. Existen circunstancias imprevisibles que pueden suceder, como que una acción requiera mucho más espacio del esperado, que un programa se vuelva loco (algo muy común si programamos), etc.</p>
+<p>Por lo tanto, concluimos que la swap no está obsoleta. Pero, ¿cuánta swap debo reservar en mi sistema?. Como ya he comentado anteriormente, la memoria de Coker se ha convertido en prácticamente una regla. Para equipos con 8GB o 16GB emplear 2GB de swap es correcto, pero, ¿lo sigue siendo para equipos con 32GB, 64GB o 256GB de RAM? 2GB se antoja poco, aparentemente.</p>
+<p>Por ello, <a href="https://help.ubuntu.com/community/SwapFaq#Example_Scenarios">Canonical propone</a> que a partir de 4GB se haga la raíz cuadrada del tamaño de la RAM, redondeada al entero más cercano; así, a 6GB de RAM le corresponderían 2GB de swap, mientras que a 32GB le corresponderían 6GB o a 256GB, 16GB. Por su parte, <a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/installation_guide/sect-disk-partitioning-setup-x86#idm140558470555584">Red Hat se asemeja</a> más a la memoria de Coker, pero siendo más generoso con equipos con menos de 8GB de RAM; siendo el doble de swap para menos de 2GB, el mismo tamaño para equipos de entre 2GB y 8GB, y la mitad para equipos de entre 8GB y 64GB.</p>
+<p>Estas recomendaciones son correctas, especialmente para servidores y sistemas eficientes. Sin embargo, tenemos que tener en cuenta que para sistemas de escritorio (y más aún en equipos portátiles), mantener un espacio de intercambio superior al tamaño de la RAM es elemental para la hibernación <sup>2</sup>. En este caso, conviene tener una swap lo suficientemente grande como para mantener el uso normal de intercambio. En ese caso, deberemos aplicar alguna de las reglas anteriores y sumarle el tamaño de la RAM.</p>
+<p>Personalmente, tanto las memorias de Coker como de RedHat me resultan algo 'cortas' cuando se trata de equipos con elevada RAM, algo realmente aplicable a prácticamente cualquier servidor o equipo de escritorio actual (no entramos en sistemas embebidos, cuya RAM es más limitada). La memoria de Canonical me parece la más generalizable y aplicable en el amplio espectro de posibilidades, y es, desde hace un par de años, la metodología que vengo aplicando en sustitución a la memoria de Coker, que usaba antes.</p>
+<p>Así, y a modo de chuleta, quedaría así mi metodología empleada:</p>
+<pre><code><b>RAM Swap Swap+Hib</b> <b>RAM Swap Swap+Hib</b> <b>RAM Swap Swap+Hib</b>
+256MB 256MB 512MB 6GB 2GB 8GB 32GB 6GB 38GB
+512MB 512MB 1GB 8GB 3GB 11GB 64GB 8GB 72GB
+1GB 1GB 2GB 12GB 3GB 15GB 128GB 12GB 140GB
+2GB 1GB 3GB 16GB 4GB 20GB 256GB 16GB 272GB
+4GB 2GB 6GB 24GB 5GB 29GB 512GB 22GB 534GB</code></pre>
+<p><sup>1</sup> Una página anónima es aquella que no corresponde con ningún archivo en disco. Eso incluye la pila, el montón o la memoria reservada dinámicamente con <emb>malloc()</emb>.</p><p><sup>2</sup> La hibernación, o suspensión en disco, consiste en apagar un ordenador conservando su estado, hecho que se logra volcando el contenido de la memoria RAM en la partición de memoria swap, que después se restaura.</p>
+
+</body>
+</html>
+\ No newline at end of file
diff --git a/tor/index.html b/tor/index.html
@@ -0,0 +1,217 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Tor</title>
+<link rel="icon" type="image/png" href="/favicon.png" />
+<link rel="stylesheet" type="text/css" href="../article.css" />
+</head>
+<body>
+<header>
+<p class="title">Contextualización teórica sobre la técnica de Tor y sus problemas de seguridad</p>
+<p class="date">26 de abril de 2018 • fjbalon</p>
+</header>
+<p>Tor son las siglas de The Onion Routing, algo que podríamos traducir al español como enrutamiento cebolla; denominado así por su criptografía en capas, como veremos más adelante. Se trata de un proyecto de software libre creado originalmente con fines militares por parte del ejército y la inteligencia norteamericanas, con el objetivo de dar comunicaciones seguras, privadas y anónimas entre espías y agentes en campo enemigo orientado a las operaciones realizadas en territorios, principalmente soviéticos.</p>
+<p>Tor consiste en una gran red descentralizada compuesta por nodos repartidos por todo el mundo, a través de los cuales viajan nuestros paquetes de red dotando de anonimato, como veremos más tarde. Tras ser abandonado por el ejército fue reciclado por la Electronic Frontier Foundation y, finalmente soportado por su propia comunidad.</p>
+<p>El objetivo de Tor es preservar la privacidad y el anonimato (diferenciados) de los que navegan por su red, manteniendo comunicaciones seguras, asegurando la integridad de la información, pretendiendo evitar monitorización y registro de actividad, etc. Con el fin de proteger la libertad de los usuarios en Internet y evitar la censura. Actualmente es utilizado por diversos perfiles, desde disidentes políticos de países autoritarios, denunciantes, periodistas, gobiernos, hackers --tanto de sombrero blanco como de sombrero negro--, vendedores de diversa índole e, incluso narcotraficantes, delincuentes, etc. El anonimato ofrecido, como en cualquier herramienta, es un arma de doble filo.</p>
+<p>Es necesario continuar esta contextualización definiendo la red profunda de la que tanto se habla -y con tan poco fundamento en muchas ocasiones-. La definición es clara y concisa: la deep web es el contenido de internet que no está indexado por los motores de búsqueda convencionales, sea por la razón que sea. Como podemos ver, no existe delincuencia ni malicia en la propia definición de esta. Un servidor privado conectado mediante Dynamic DNS que permite trabajar con direcciones IP dinámicas. de un particular o cualquier base de datos empresarial (que lógicamente no es accesiblemediante indexadores) podría considerarse y, de hecho, se considera parte de la red profunda.</p>
+<p>Cuando la cultura popular se refiere a la red Tor como homóloga a la Deep Web, lo hace erróneamente. Sí es cierto que debemos admitir a la red Tor (y cualquier red semejante o parecida, como las redes i2p o freenet) como parte de la deep web. Para solucionar este conflicto de conceptos, se ideó la conocida como darknet o red oscura, haciéndo referencia exclusivamente a estas redes especiales; concepto que vuelve a ser salpicado por la leyenda negra que lo absorve -que no exime de la existencia de inmoralidad y delincuencia en ella, hay que admitir-. Por ello, en el presente documento se hablará con propiedad a la hora de mencionar la deep web y la darknet.</p>
+<p>A priori la técnica detrás de Tor puede parecer muy complejo, pero en lo que avanza el desarrollo de este documento podremos comprobar que su funcionamiento es sencillo; no eximiendo un grandísimo potencial de uso y, como veremos más adelante, un gran margen de mejora.</p>
+<p>Si nos conectamos a Internet de manera habitual, nuestra dirección IP pública y un conjunto de información más quedará expuesta, tanto para el destino de la conexión como para Man in the Middle, las propias empresas que nos proveen servicios, autoridades, gobiernos, etc. Además si la conexión no se encuentra cifrada podrá incluso filtrarse contraseñas y mensajes secretos y confidenciales. Todo lo que hacemos en Internet puede ser --y se encuentra, de hecho-- monitorizado y almacenado.</p>
+<p>Por contraposición, Tor crea una ruta al azar de nodos distribuidos por el mundo, a través de los cuales viajarán nuestras peticiones, de esta forma el destino de nuestros paquetes no conocerá nuestra dirección IP, sino la del nodo de salida (al igual que usando un proxy o una VPN), y de la misma forma, el nodo de salida no conocerá la dirección IP del origen, sino del nodo anterior a él en la ruta. A su vez, el nodo de entrada no conocerá el destino de la conexión, simplemente su destino será el segundo nodo. De esta forma se permite alcanzar un alto grado de anonimato, ya que, en el caso de ser vulnerado o amenazado un nodo, nuestra información se mantendrá anónima.</p>
+<p>Anteriormente comentamos el origen del nombre de Tor: el enrutador cebolla. Esto se debe a su peculiar forma de usar la criptografía sobre la información que realiza para que proteger la confidencialidad e integridad de la información de los propios servidores, incluso: cifrado por capas. Completando la explicación anterior, nuestro cliente de Tor alojado en nuestra máquina calculará al azar la ruta antes mencionada, que en este caso digamos que corresponde a 3 nodos para agilizar la explicación, el nodo de entrada en Washington, el segundo nodo en Praga y el nodo de salida en Moscú. Con la ruta ya calculada, cifrara el paquete, digamos, la petición de una simple página HTML con la clave pública del nodo de salida, posteriormente volverá a cifrar el paquete ya cifrado con la clave pública del segundo nodo y, finalmente, con la clave del nodo de entrada y, una vez terminado el cifrado por capas, será enviado al nodo de entrada, donde usará su clave privada para descifrarlo y lo reenviará al segundo nodo, que hará lo mismo.</p>
+<img class="color-invertible" src="resources/torconn.png" />
+<p>El proceso continuará hasta llegar al nodo de salida y este (Moscú) pedirá la página deseada (recordamos que este servidor verá como cliente a Moscú y no a nosotros) y realizará el mismo proceso de cifrado pero a la inversa, para devolverla al cliente de Tor. A continuación será desglosado este tema tan amplio como la criptografía, en concreto lógicamente la de la red que estamos estudiando.</p>
+<p>Tor es el heredero del sistema desarrollado por el Departamento de Defensa de Estados Unidos. Ahondando un poco más en el tema, podemos llamar a David M. Goldshlag, Michael Reed y Paul Syverson los padres del encaminamiento cebolla, idea algorítmica que precede y, es a su vez, núcleo del concepto y de la técnica de Tor. Éstos se basaron y aplicaron las ideas de redes de mezclado de David Chaum. El objetivo fundamental y sin añadidos de estos conceptos criptográficos no es más que permitir infraestructuras para comunicaciones privadas sobre redes públicas.</p>
+<p>Tor no es la única red basada en estos conceptos criptográficos y algorítmicos, pero sí es la más conocida, la más utilizada y, en principio, la que mejor resultados otorgan a los usuarios. Además, el tratarse de una red de software libre y de código abierto ha permitido la afluencia de una gran comunidad de desarrolladores que la han hecho crecer y mejorar. Dicho esto, podemos hacer menciones honoríficas a otras redes que, como Tor, siguen esta idea: Freedom Network, Onion Routing, MixMaster, Babel, Mixminion, Zach Brown's Onion, PipeNet, IronKey, MorphMix, y Tarzan.</p>
+<h2>Idea primigenia</h2>
+<p>La idea primigenia era utilizar criptografía de clave asimétrica tradicional. Este sistema es vulnerable a ataques basados en sniffing de tráfico. Efectivamente, supongamos que un atacante puede esnifar todos los datos que son intercambiados entre los nodos. Si finalmente el atacante consigue comprometer todos los routers (accediendo a sus claves privadas) entonces este puede descifrar todo el tráfico almacenado anteriormente. </p>
+<p>Para acotar este problema podríamos cambiar periódicamente las claves (pública y privada) de los routers. Para ello estableceríamos un periodo de tiempo a la finalización del cual las claves caducarían y sería necesario establecer nuevas claves. La clave pública habría que difundirla y la antigua clave privada se destruiría para que no pudiera ser obtenida nunca, asegurando así la persistencia de la seguridad del tráfico que se realizó usando la antigua clave. Sería acertado que el cambio de claves fuera frecuente ya que esto limitaría la cantidad de tiempo que tiene A para comprometer B y C, pero a la vez requeriría que los routers del sistema contactaran frecuentemente con un sistema que les actualizara las nuevas claves lo que llevaría a problemas de escalabilidad. En resumidas cuentas: viable pero poco práctico.</p>
+<h2>Criptografía de Onion Routing, padre de Tor</h2>
+<p>Onion Routing establece un circuito de claves simétricas, a partir de una criptografía de clave pública mediante una estructura de datos con capas (de ahí la denominación de cebolla - onion que posteriormente fue reutilizada por nuestro objeto de estudio).</p>
+
+ <math xmlns="http://www.w3.org/1998/Math/MathML" alttext="E_{PK_{R_{1,(K_{1,R_{2,E_{PK_{R_{2,(K_{2,R_{3,E_{PK_{R_{3,(K_{3,% Pad)))" display="block">
+ <mrow>
+ <msub>
+ <mi>E</mi>
+ <mrow>
+ <mi>P</mi>
+ <mo></mo>
+ <msub>
+ <mi>K</mi>
+ <msub>
+ <mi>R</mi>
+ <mn>1</mn>
+ </msub>
+ </msub>
+ </mrow>
+ </msub>
+ <mo>,</mo>
+ <mrow>
+ <mo stretchy="false">(</mo>
+ <msub>
+ <mi>K</mi>
+ <mn>1</mn>
+ </msub>
+ <mo>,</mo>
+ <msub>
+ <mi>R</mi>
+ <mn>2</mn>
+ </msub>
+ <mo>,</mo>
+ <msub>
+ <mi>E</mi>
+ <mrow>
+ <mi>P</mi>
+ <mo></mo>
+ <msub>
+ <mi>K</mi>
+ <msub>
+ <mi>R</mi>
+ <mn>2</mn>
+ </msub>
+ </msub>
+ </mrow>
+ </msub>
+ <mo>,</mo>
+ <mrow>
+ <mo stretchy="false">(</mo>
+ <msub>
+ <mi>K</mi>
+ <mn>2</mn>
+ </msub>
+ <mo>,</mo>
+ <msub>
+ <mi>R</mi>
+ <mn>3</mn>
+ </msub>
+ <mo>,</mo>
+ <msub>
+ <mi>E</mi>
+ <mrow>
+ <mi>P</mi>
+ <mo></mo>
+ <msub>
+ <mi>K</mi>
+ <msub>
+ <mi>R</mi>
+ <mn>3</mn>
+ </msub>
+ </msub>
+ </mrow>
+ </msub>
+ <mo>,</mo>
+ <mrow>
+ <mo stretchy="false">(</mo>
+ <msub>
+ <mi>K</mi>
+ <mn>3</mn>
+ </msub>
+ <mo>,</mo>
+ <mrow>
+ <mi>P</mi>
+ <mo></mo>
+ <mi>a</mi>
+ <mo></mo>
+ <mi>d</mi>
+ </mrow>
+ <mo stretchy="false">)</mo>
+ </mrow>
+ <mo stretchy="false">)</mo>
+ </mrow>
+ <mo stretchy="false">)</mo>
+ </mrow>
+ </mrow>
+ </math>
+
+ <math xmlns="http://www.w3.org/1998/Math/MathML" alttext="PK_{Ri=Ri;Ri\in\{R_{1,R_{2,R_{3\" display="block">
+ <mrow>
+ <mrow>
+ <mrow>
+ <mi>P</mi>
+ <mo></mo>
+ <msub>
+ <mi>K</mi>
+ <mrow>
+ <mi>R</mi>
+ <mo></mo>
+ <mi>i</mi>
+ </mrow>
+ </msub>
+ </mrow>
+ <mo>=</mo>
+ <mrow>
+ <mi>R</mi>
+ <mo></mo>
+ <mi>i</mi>
+ </mrow>
+ </mrow>
+ <mo>;</mo>
+ <mrow>
+ <mrow>
+ <mi>R</mi>
+ <mo></mo>
+ <mi>i</mi>
+ </mrow>
+ <mo>∈</mo>
+ <mrow>
+ <mo stretchy="false">{</mo>
+ <msub>
+ <mi>R</mi>
+ <mn>1</mn>
+ </msub>
+ <mo>,</mo>
+ <msub>
+ <mi>R</mi>
+ <mn>2</mn>
+ </msub>
+ <mo>,</mo>
+ <msub>
+ <mi>R</mi>
+ <mn>3</mn>
+ </msub>
+ <mo stretchy="false"></mo>
+ </mrow>
+ </mrow>
+ </mrow>
+ </math>
+<p>Donde K<sub>i</sub> es material que permite establecer la/s clave/s de sesión compartida (puede haber una para cada sentido de la comunicación) entre el origen de la comunicación (el iniciador).</p>
+<p>Observe que la capa final se identifica porque no contiene ni dirección destino, ni datos con significado para ser transmitidos.</p>
+<p>La principal desventaja de este enfoque es que no provee de perfect forward secrecy. Supongamos que un circuito se construye desde el iniciador con la secuencia de nodos A,B,C y que A es un router malicioso y por tanto el atacante puede descifrar todo lo que pasa y ha pasado por él. Si A graba todo el tráfico y en el último momento se compromete B (el cual sabe quien es el último nodo C), entonces se compromete C y A puede saber con quien se está comunicando el iniciador.</p>
+<h2>Enfoque telescópico</h2>
+<p>Y finalmente llegamos a la criptografía utilizada por Tor. Ésta utiliza una construcción incremental e interactiva del circuito, a la que llaman enfoque telescópico.</p>
+<img class="color-invertible" src="resources/onion.png" style="width: 40%;" />
+<p>En concreto Tor se apoya en el Tor Authentication Protocol (siglas TAP), cuya seguridad fue probada en el modelo de oráculo aleatorio. Tor lo que hace es realizar una ejecución secuencial de múltiples instancias de TAP, estableciendo un circuito de autenticación RSA de un solo sentido (el iniciador no se autentica nunca). Para ello se utiliza el circuito parcialmente construido hasta ese momento. Podemos decir que en cada tramo sucesivo del circuito se realiza una negociación interactiva de claves (protocolo de establecimiento de claves de Diffie-Hellman).</p>
+<p>En el TAP la clave pública del nodo sólo se utiliza para iniciar la comunicación durante la cual se establece la clave temporal de sesión vía el protocolo de establecimiento de claves de Diffie-Hellman. Las claves se forman a partir del intercambio de mensajes en lugar de ser enviadas de forma cifrada. Por tanto, una vez que la sesión finalice (el circuito ha dejado de usarse) y se destruyan las claves de sesión, si se compromete un router (se obtiene su clave privada) esto no permite al adversario recuperar las claves de sesión eliminadas y descifrar así el tráfico cifrado bajo esa clave que pudiera tener almacenada. Por tanto tenemos perfect forward secrecy. Por otra parte ya no es necesario almacenar hashes de las estructuras de datos previamente procesadas para evitar ataques de replay. Reinyectando uno de los mensajes del handshake del protocolo de establecimiento de claves de Diffi-Hellman provoca unos resultados de clave de sesión diferentes y por tanto ya no sería un ataque efectivo.</p>
+<p>Tor permite la salida a Internet utilizando los repetidores que se encuentran dentro de la red. Esto es una solución outproxy en donde los usuarios pueden salir hacia Internet utilizando la plataforma de anonimato, los repetidores que se encuentran disponibles en la red.</p>
+<p>Las redes inproxy, por el contrario no permiten esto, solamente permiten la navegación dentro de la red. Es el concepto más puro de una VPN es una tecnología que permite la extracción cifrada y tunelada de una red de área local (LAN) a una red pública. en donde todos los repetidores se pueden comunicar entre ellos pero no permiten salir de ella.</p>
+<p>Por ello podemos concluir en que Tor es una red inproxy a la misma vez que es una red outproxy; dependiendo del uso que le demos podemos obtener las ventajas de una u otra, o ambas simultáneamente.</p>
+<h2>Hidden services</h2>
+<p>Tor implementa además un protocolo que permite la configuración de servidores dentro de la misma red, sin necesidad de salir de ella (algo que aumenta notoriamente la privacidad y el anonimato, tanto del lado del cliente, como del lado del servidor). Podemos considerarlo quizás, una red privada, una intranet propia de la red. Estos servidores se conocen como hidden services (Servicios ocultos, en castellano).</p>
+<p>Un hidden service es un servidor común, la mayor parte de ellos corriendo sobre GNU/Linux y el resto FreeBSD, Unix, GNU/Hurd, etc. En ocasiones incluso podemos encontrar servidores ocultos corriendo sobre Microsoft Windows Server, aunque es algo poco común. Estas máquinas ofrecen los mismos servicios que un servidor convencional (web, mail, FTP, etc).</p>
+<p>Pero, al contrario de un servidor común, el cliente no conoce la dirección IP del mismo. Los nodos de Tor cumplen la función de servidores DNS, que de mediante intercambio de claves criptográficas obtiene la clave pública que identifica a este servidor dentro de la red de nombres de dominio. Esta clave seguida de la extensión .onion constituye el dominio del servidor.</p>
+<code><p style="text-align:center">x67ebbbjksjdjsl.onion</p></code>
+<p>Como podemos ver, el dominio asociado no es fácil de recordar, no sigue una lógica semántica ni sintáctica. Por esta misma razón, existen las llamadas Hidden wiki's, que no son más que bases de datos de servidores y dominios, normalmente clasificados en categorías. Es una forma sencilla de indexar en la medida de lo posible estos contenidos, aunque de una forma burda, costosa y rudimentaria.</p>
+<p>A pesar de que Tor está basado y construido con base en la seguridad, el anonimato y la privacidad de sus usuarios, como todo sistema no está extenso de problemas generales y específicos de seguridad, de riesgos y vulnerabilidades.</p>
+<p>En cuanto a la seguridad general, evidentemente por mucho que nos conectemos a Tor si accedemos a servicios no seguros o no privados (Facebook tiene su propio dominio onion -<a href="facebookcorewwwi.onion">facebookcorewwwi.onion</a>-, algo curioso), los paquetes que salen por el nodo final serán inseguros o poco privados. En este caso, sólo protegerás tu conexión de salida a Internet. Esto es así porque quien tenga acceso -sea propietario o hackeado- al nodo de salida, tiene acceso a los paquetes en bruto, pudiendo espiar la conexión no cifrada o realizar otro tipo de ataques a este nivel. Es decir, un actor malicioso que controle el nodo de salida de Tor podría ser un riesgo potencial para el anonimato. Por contraposición, un actor que controla el nodo de entrada, aún manteniendo la privacidad del usuario, podría ser un riesgo en el intercambio de paquetes y manipulación de estos.</p>
+<p>Del mismo modo, la descarga de código local como javascript en diversas páginas se puede convertir en un riesgo para el anonimato. También complementos como Adobe Flash y aplicaciones externas como Adobe Reader o incluso un reproductor de video podrían potencialmente filtrar su dirección IP real a un sitio web que intenta adquirirla. El paquete del navegador Tor evita todos estos problemas con su configuración predeterminada, pero podría deshabilitar estas protecciones y usar JavaScript o complementos en el navegador Tor.</p>
+<p>Debido al propio diseño estructural de Tor, permitiría que la realización de ataques Man in the Middle complejos, que permitirían -si una persona u organización controla el nodo de salida y de entrada- relacionar las direcciones IP con las peticiones enviadas al servidor, así como los timestamps y los tiempos de comunicación, y llegando a corresponder la conexión de entrada con la conexión de salida; rompiendo el anonimato y la privacidad del usuario. Aunque esto parece un riesgo mínimo por tratarse de una causística muy concreta, no lo es tanto. Véase <a href="https://www.genbeta.com/seguridad/alguien-lleva-cuatro-anos-gestionando-cientos-servidores-tor-hackeados-para-desanonimizar-a-usuarios-esta-red-privada">KAX17 ha llegado a controlar hasta el 10% de nodos de salida con motivos maliciosos</a>, lo que le da a KAX17 un alto control de la red. Este tipo de ataque se denomina Sybil; aquel que controle mayor número de nodos tiene más posibilidades de formar parte en más circuitos. No obstante la propia red dispone de un sistema de scripts que automatiza y comprueba si hay un aumento repentino o anormal de nodos, y un equipo de revisión de nodos para mitigar el riesgo potencial.</p>
+<img class="color-invertible" style="width: 50%;" src="resources/torspoiled.png" />
+<p>Otro ataque a tener en cuenta es el ataque predecesor, que tiene como objetivo identificar a los clientes de la red Tor aprovechando la reconstrucción de los circuitos. Uno o varios nodos hacen un seguimiento de las conexiones. Cada vez que un usuario reconstruye (aleatoriamente cada 10 minutos de conexión) un circuito, se vuelve a conectar a nuevos nodos haciendo que el atacante identifique al cliente porque tenderá a conectarse más veces que cualquier otro nodo. Conectado con el ataque Sybil, aquel que controle muchos nodos podría hacerlos fallar habitualmente para obligar a los clientes a reconectarse una y otra vez aumentando el éxito del ataque hasta obtener un circuito totalmente controlado por él (ataque de reconstrucción circuital).</p>
+<p>El ataque por atasco es también un elemento de riesgo. Una conexión a través de n routers tiene un efecto en las otras conexiones a través de ese mismo router, personalmente me gusta llamarlo onda lógica. El usuario atacante tiene que controlar un router Tor y ser capaz de observar una conexión intermedia entre la salida del router y el destino final. Mediante el router Tor, el atacante, puede crear circuitos en todos los demás routers Tor uno por uno para comprobar la latencia de la conexión si incrementa o no. En el momento que encuentre un router donde sí aumente, ese router está en el circuito. Aun así, debido al número de nodos actual es un ataque que por infraestructura tiene un bajo riesgo, pero alto impacto.</p>
+<p>El ataque Round-Trip Travel Time depende del tiempo de ida y vuelta de los clientes a los servidores. También hay que tener en cuenta posibles ataques de envenenamiento DNS, parcheo de archivos añadiendo código malicioso, sustitución de certificados SSL...</p>
+<p>Evidentemente, también el uso de aplicaciones vulnerables, o posibles apariciones de ataques 0-day contra éstas, que usan la red Tor entablaría un riesgo potencial para la privacidad y el anonimato. El navegador de Tor, basado en Firefox, no está exento de estas vulnerabilidades. Véase <a href="https://www.cvedetails.com/vulnerability-list/vendor_id-12287/product_id-50922/Torproject-Tor-Browser.html">CVE Details, Tor Browser: Security Vulnerabilities</a>.</p>
+<p>Como conclusiones, la red Tor ofrece una estructura estable para dotar de seguridad, privacidad y anonimato a los usuarios. Pero como hemos visto no está exenta de vulnerabilidades y riesgos. Cualquier usuario conectado a Tor deberá tomar medidas de seguridad, igual que si de una conexión por la surface web se tratase. Tor es combinable con otros elementos de seguridad de conexión, como VPN, combinando los circuitos de Tor y encadenando la salida de Tor -insegura- con la conexión cifrada de la VPN. También el uso de sistemas y softwares fiables es fundamental para garantizar un alto nivel de seguridad.</p>
+<p>Y finalmente, evidentemente tener sentido común a la hora de realizar conexiones, evitando ataques de ingeniería social o errores humanos que pongan en peligro la seguridad. El hombre es siempre el eslabón más débil en la cadena de la seguridad, por lo que es un elemento crítico a tener en cuenta y a proteger.</p>
+<p>Puede profundizar el tema en:</p>
+<ul>
+<li><a href="https://torproject.org/docs/documentation.html">Tor Project</a></li>
+<li><a href="https://wiki.archlinux.org/index.php/tor">ArchWiki</a> sobre Tor</li>
+<li><a href="https://makeuseof.com/tag/i2p-vs-tor-vs-vpn-secure/">I2P vs. Tor vs. VPN: Which Is More Secure?</a></li>
+<li><a href="https://fwhibbit.es/24-horas-en-la-vida-de-un-nodo-de-salida-de-tor">24 horas en la vida de un nodo de salida de Tor</a>, fwhibbit</li>
+<li><a href="https://thehackernews.com/2021/05/over-25-of-tor-exit-relays-are-spying.html">Over 25% Of Tor Exit Relays Spied On Users' Dark Web Activities</a></li>
+</ul>
+
+</body>
+</html>
+\ No newline at end of file
diff --git a/tor/resources/onion.png b/tor/resources/onion.png
Binary files differ.
diff --git a/tor/resources/torconn.png b/tor/resources/torconn.png
Binary files differ.
diff --git a/tor/resources/torspoiled.png b/tor/resources/torspoiled.png
Binary files differ.