Información blog

Linux, tutoriales, noticias, sistemas, redes y seguridad informática, entre otras cosas.

Mostrando entradas con la etiqueta Internet. Mostrar todas las entradas
Mostrando entradas con la etiqueta Internet. Mostrar todas las entradas

martes, 29 de octubre de 2019

Cómo realizar pruebas de carga en nuestro servidor Web

Una de las labores más importantes a la hora de montar un servidor web, es la dimensionarlo correctamente para poder realizar sus labores de forma efectiva. Generalmente a la hora de realizar el dimensionamiento se suele tender a optimizar el servidor lo máximo posible, con los recursos disponibles, para poder soportar el máximo de conexiones posibles, pero aun así, siempre es importante intentar forzar dicho servidor por encima de su capacidad máxima con el fin de ver cómo reacciona... Esto puede ser una labor sencilla si el servidor soporta muy pocas conexiones, pero y si soportase 1000 conexiones simultáneas o más? Afortunadamente existen herramientas especializadas de Linux que nos pueden ayudar a realizar testear nuestro servidor web... Entre ellas hay dos especialmente conocidas: Apache Benchmark  y JMeter.

portada_pruebas_carga

Apache Benchmark

Si bien esta utilidad se puede considerar bastante inferior a JMeter, se trata de una utilidad que tiene la ventaja de que te permite realizar pruebas rápidas desde la consola sin tener la necesidad de tener una interfaz gráfica, cosa que evita el obligarnos a depender de un entorno de escritorio para poder utilizarla. La herramienta en sí es muy fácil de instalar, ya que es parte del conjunto de utilidades estándares de Apache2, llamada apache2-utils, con lo que lo podemos instalar de los repositorios tal que así:

apt-get install apache2-utils

Con esto instalado, podemos hacer pruebas de carga de forma muy rápida mediante el comando ab; donde la sintaxis sería:

ab -c concurrencias -n numero_de_peticiones -r URL

El parámetro -r sería importante, ya que evitaría que el comando se interrumpiese aún cuando hubiese algún error... Además es importante resaltar que la URL tiene que apuntar siempre a un fichero web... Por ejemplo si tenemos un servidor web con IP 127.0.0.1, no valdría con poner dicha IP como URL sino que habría que poner http://127.0.0.1/index.html pues en caso contrario Apache Benchmark pensaría que la URL es errónea.

En caso de querer hacer 1000 peticiones con 20 concurrencias a la URL atrás mencionada, haríamos:

ab -c 20 -n 1000 -r http://127.0.0.1/index.html

Esto nos daría como resultado una serie de líneas, entre las cuales se resaltarían las últimas donde se muestran el porcentaje de paquetes que ha tardado X milisegundos en tener respuesta:

prueba_carga_ab
Resultado prueba carga Apache Benchmark

Lo malo que tiene esta herramienta, es que carece de opciones de personalización a la hora de realizar las pruebas de carga; es decir, no puedes decir si las peticiones se van a hacer de forma controlada, o como un ataque DOS... Simplemente las realiza lo más rápido que puede y listo... Lo cual viene por un lado bien para saber cómo se comporta bajo cierta presión, pero que no emula entornos realistas. Es por eso que esta herramienta tienes sus pros y sus contras y es ahí donde JMeter marca la diferencia, ya que dicha herramienta sí que tiene un mayor abanico de opciones.

Apache JMeter

En este caso para poder siquiera instalar la aplicación es 100% necesario tener instalado un entorno de escritorio, pues instalar elementos gráficos. El entorno de escritorio en sí es indiferente, puede ser XFCE, KDE, Gnome... Al gusto de cada uno... Cumpliendo dicho requisito habría que escribir en la consola:

apt-get install jmeter

Esto preparará todo lo necesario para que Jmeter sea utilizable, si bien Jmeter tiene una peculiaridad. La configuración de los diferentes parámetros y planes de pruebas se realizan desde de la GUI, pero la ejecución del plan de pruebas es extremadamente recomendable hacerlo desde la consola; recomendación que es dada por los propios desarrolladores de la utilidad.

Con lo que teniendo esto claro, primero abriríamos la aplicación desde la GUI, aplicación que, desgraciadamente, al ser tan completa, puede ser algo intimidante inicialmente.

El primer paso que habría que ejecutar sería la creación de un Grupo de Hilos; dicho paso es vital pues marca el número de peticiones simultáneas que se harían, el intervalo entre éstos y el número de veces que se lanzarían peticiones (pudiendo ser infinito); las capturas de a continuación serían realizadas desde un Ubuntu 18.04, capturas en las que, en este caso mostraríamos 100 peticiones simultáneas realizadas cada segundo continuamente :

nuevo_grupo_hilos
Nuevo grupo hilos

configuracion_grupo_hilos
Configuración grupo hilos

Con esto tendríamos las peticiones preparadas; lo que habría que especificar sería qué peticiones se desean realizar... Aquí tenemos diferentes opciones, pero la más común y usada sería una petición HTTP; petición en la que únicamente sería necesario especificar que sería del tipo GET y la IP y puerto de destino de dichas peticiones; habría una serie de parámetros adicionales, pero todos ellos serían completamente optativos:

nueva_peticion_http
Petición HTTP


opciones_peticion_http
Opciones petición HTTP

Por último pero no por ello menos importante, tendríamos que crear un reporte de resumen, el cual nos servirá para conocer los resultados de nuestras pruebas. El cual se encontraría dentro de: Añadir --> Receptor --> Reporte Resumen.  El resumen se puede ver en texto plano desde la propia consola, pero desde la herramienta tendríamos el resultado mostrado de forma sintetizada, lo cual nos es ventajoso.

Ahora que tenemos todo preparado, guardaríamos el proyecto, el cual siempre es guardado en formato .jmx, por ejemplo plan_de_pruebas.jmx. Solamente sería necesario ejecutar dicho plan, ejecución que aunque se puede hacer desde la GUI, tal y como he comentado antes es recomendable hacerlo desde la consola. El comando para ejecutarlo sería:

jmeter -n -t plan_de_pruebas.jmx -l Resumen.jtl

El parámetro -l seguido del fichero jtl sería importante, pues estaríamos especificando donde guardar los resultados de las pruebas realizadas; pruebas que siempre se guardan en ficheros en formato .jtl, si bien se puede leer de forma "normal" haciendo un simple cat sobre dicho fichero.

Gracias a dicho comando estaríamos ejecutando el plan de pruebas, que se estaría ejecutando de forma continua a menos que se pulsase la combinación de teclas CTRL + C, debido a que se trata de una prueba infinita. Esto estaría haciendo una prueba de carga "infinita" sobre el servidor de destino, prueba sobre la que tendríamos más control que mediante Apache Benchmark.

El informe de salida lo podríamos leer dirigiéndonos al `Reporte resumen` antes creado y clickando en navegar para seleccionar el informe generado por nuestras pruebas; en nuestro caso Resumen.jtl... A continuación una pequeña muestra de dicho informe:

reporte_resumen
Informe Jmeter


Como se puede observar, la aplicación JMeter ofrece una amplia gama de posibilidades; estas son solo algunas de ellas, pero las mostradas serían las más "comunes" y usadas. Eso no implica que Apache Benchmark no sea útil; cada una ofrece una serie de características, la cuestión está en saber qué aplicación se adapta mejora nuestras necesidades, al igual que también no siempre se puede contar con una interfaz gráfica, y ahí es donde JMeter flaquea, pues dicho entorno es un requisito para la propia instalación.

Espero que os haya resultado útil.

Saludos.

lunes, 21 de octubre de 2019

Cómo solucionar el error too many open files en Linux

En un servidor en producción de Linux con bastante carga pueden ocurrir errores tipo "Too many open files" o que los servicios no puedan abrir más sockets (ficheros) de conexión. Esto se debe a que en Linux se pueden establecer limites de ficheros abiertos simultáneamente y ésta limitación es por usuario.  Puede parecer un error raro, pero en caso de tener un servidor SQL y/o web, no es un error tan extraño, dependiendo del volumen de información tratado.

toomanyopenfiles

Para solucionarlo hay que cambiar la configuración en varios sitios, pero primero hay que comprobar la configuración actual:

ulimit -n

Esto nos indicará la cantidad máxima por usuario y sesión. El valor por defecto es 1024, lo que aunque en un principio, pueden parecer muchos, no siempre dan basto, especialmente cuando se trabaja con un sistema que tiene un servidor web/SQL instalado, ya que éstos trabajan con muchos ficheros temporales y los necesita mantener abiertos por cuestiones de rendimiento. Para cambiar este valor:

ulimit -n 75000

Este comando aplicará el cambio en términos de la sesión actual. Para hacerlo persistente tenemos que editar los límites a nivel de configuración del sistema, lo cual se realizaría en /etc/security/limits.conf

root soft core unlimited
root hard core unlimited
root soft memlock 131072
root hard memlock 131072
root soft nofile 999999
root hard nofile 999999

Luego, aparte de limites por usuario y sesión, existen limites a nivel del propio sistema operativo. Para ajustarlos habría que editar el fichero /etc/sysctl.conf, el cual realiza cambios a nivel de kernel,  y añadir esta línea al final:

fs.file-max = 999999

Con esto ya tendríamos el cambio aplicado, para que haga efecto podemos o bien recurrir al clásico reinicio o bien ejecutar el comando:

sysctl -p

Con esto ya tendríamos los nuevos límites establecidos en el sistema, evadiendo así los errores del tipo too many open files.

Espero que os haya resultado útil.

Saludos.

martes, 1 de octubre de 2019

Nftables, el sucesor de iptables

La tecnología evoluciona constantemente, a veces a costa de imposiciones de ciertos criterios, y otros a costa de comparar los pros y los contras. Iptables ha sido siempre el principal referente en el área de firewalls para Linux; es cierto que a raíz de ahí nacieron herramientas intuitivas que intentaban hacer un uso más fácil de éste, pero generalmente se usaba dicha tecnología como referencia. Obviamente, con el paso del tiempo, se han ido optando por diferentes alternativas, pero siempre intentando mantener iptables ahí, pero con la introducción de "Debian 10 (Buster)" y las últimas versiones de Red Hat, se ha ido imponiendo su sucesor, considerando al veterano firewall como obsoleto. Hablamos de nftables.

nftables_portada

Nftables es un software creado por netfilter que podría considerarse como la evolución natural de nftables, que ha intentado adaptar la sintaxis a los nuevos tiempos, con el fin de que la escritura de las reglas de este software sea algo más intuitiva que la de su predecesor.

La dinámica que utilizar este software es bastante parecida a la de iptables, en el sentido de que tal y como ocurre con su predecesor,  nftables se divide por tablas, las cuales tienen dentro cadenas, dentro de las cuales se añaden las reglas. En caso de haber usado iptables con anterioridad dichos conceptos os serán familiares, en caso contrario es importante tenerlos claros antes de continuar, ya que en caso contrario el entendimiento de la herramienta será muy difícil. Además es importante saber que las reglas de nftables se pueden definir o bien directamente en consola o bien mediante un fichero de configuración.


TABLAS

Las tablas están compuesta por una o varias cadenas; en iptables éstas seguían una lógica, ya que se agrupaban en cadenas de tipo filter, nat y mangle; en nftables podemos hacer que nuestras tablas tengan las cadenas que queramos, pero lo ideal, en términos de gestión es que sigan una lógica parecida, aunque no es obligatorio. En resumen, una tabla no es más que una o a varias cadenas agrupadas bajo un nombre común desde el cual se hacer referencia a éstas.  Las tablas pueden tener el nombre que queramos, pero es importante tener en cuenta que éstas pertenecen a diferentes familias, y que dependiendo del tipo, se tendrán en cuenta un tipo de paquete de red u otro:
  • ip: La familia por defecto, en caso de que no le digamos nosotros otra cosa. Éste solamente tendrá en cuenta los paquetes de red IPv4.
  • ip6: Como su propio nombre indica, tendrá en cuenta los paquetes IPv6.
  • inet: Una familia híbrida que contemplará ambos protocolos de IP, y que, dependiendo de a lo que hagamos referencia, tendrá en cuenta un tipo de IP u otra, o ambas, Por ejemplo si se hace referencia a una IPv4, se aplicará la regla para los paquetes IPv4, pero si hacemos referencia solamente a un puerto (por ejemplo el 80), sin especificar una IP de origen o de destino, se tendrán en cuenta ambos protocolos. Esta familia no funciona en las cadenas NAT (de esto hablaremos más adelante), al menos de momento, debido al bug 1173, con lo en caso de querer usar cadenas de dicho tipo para paquetes IPv4 e IPv6, habría que crear 2 tablas separadas, una perteneciente a la familia ip y la otra a ip6.
  • arp: Esta familia solamente tendrá en cuenta el tráfico ARP.
  • bridge: Esta familia entraría en acción en las interfaces de tipo bridge, que hayan sido creadas en el sistema.
  • netdev: Aquí se tratará el paquete antes de que sea procesado por la interfaz de red. No se tiene en cuenta si es IPv4 ni IPv6; desde aquí se ve todo, y es útil para el bloqueo de ataques DOS o DDOS, ya que lo deniega antes de ser procesado, tomándole menos tiempo al sistema el desecharlo.

La primera vez que se instala nftables, crea una tabla llamada filter del tipo inet, pero es importante conocer cómo agregar nuevas tablas. 

Para ello, antes de empezar a hacer nada, es muy recomendable cargar todos sus módulos de nftables en el kernel, ya que en caso contrario nos podremos encontrar errores tales como 'Could not process rule: No such file or directory'. Para ello lo recomendado por los propios desarrolladores del proyecto, es crear el fichero /etc/modules-load.d/modules-nftables.conf e introducir el siguiente contenido para después reiniciar el equipo:

nf_conntrack
nf_conntrack_ipv4
nf_conntrack_ipv6
nf_defrag_ipv4
nf_defrag_ipv6
nf_nat
nf_nat_ipv4
nf_tables
nf_tables_inet
nf_tables_ipv4
nf_tables_ipv6
nfnetlink
nft_counter
nft_ct
nft_hash
nft_limit
nft_log
nft_meta
nft_rbtree
nft_reject
nft_reject_inet
nft_reject_ipv4
nft_reject_ipv6

Con todos los preparativos realizados, para crear una nueva tabla escribiremos la siguiente sintaxis:

nft add table 'familia' 'nombre'

Por ejemplo, para crear una tabla llamada "filter" que contemple los paquetes IPv4 e IPv6, haremos:

nft add table inet filter

Con ello ya tendríamos nuestra primera tabla creada, tabla que puede ser borrada o que cuyo contenido puede ser listado o borrado sustituyendo add por delete, list y flush, respectivamente.


CADENAS

Las cadenas son simples contenedores de reglas. A diferencia de en iptables, que ya había una serie de cadenas predefinidas, tales como INPUT, OUTPUT, en nftables no existe ninguna por defecto, sino que tienen que ser creadas. La creación de cualquier cadena tendría una sintaxis como la siguiente:

nft add chain 'familia' 'tabla' 'nombre_cadena' {type 'tipo' hook 'estado_del_paquete' priority 'prioridad'; policy 'politica';} 

Las familias y las tablas ya las conocemos, con respecto al tipo, tenemos cadenas de tres tipos:
  • filter: Este tipo de cadena se encarga del filtrado de paquetes.
  • route: Permite rutar los paquetes salientes
  • nat: Se utiliza para aplicar reglas de nateo de paquetes, es decir, para la conversión de IPs.

Por otro lado tenemos el estado del paquete, el cual viene 'heredado' de su predecesor, iptables, y que dependiendo del tipo que hayamos escogido, se podrá hacer referencia a un estado u otro del paquete. Los estado sería input, output, forward, prerouting y postrouting. Los tres primeros son intuitivos, mientras que prerouting se utilizaría para tratar una interfaz que está a punto de ser rutada  y postrouting se utilizaría para tratar la interfaz tras haber sido rutada.  

Obviamente no todos los tipos se pueden usar en todas las familia al igual que no todos los estados se pueden usar para todos los tipos, con lo que a continuación dejo una pequeña tabla que puede servirnos como guía orientativa que nos puede servir de ayuda en la creación de cadenas:

tabla_hooks_nft

Además, podemos definir la prioridad que tendrá la cadena con respecto al resto de la misma tabla. Aquella que tenga el número más bajo (pudiendo ser negativo), será aquella que se ejecutará antes.

Además podemos también definir, de forma opcional, la política que queremos que tenga la cadena por defecto, de entres las cuales las más comunes serían: accept o drop, es decir permitir o denegar. En caso de no definir ninguna política, nftables define automáticamente que la política será accept.

Con toda esta información en mano, podemos crear varias cadenas de prueba. Por ejemplo, siguiendo la lógica del ejemplo inicial, en el que hemos creado una tabla llamada filter, vamos a crear las 3 cadenas de filtrado básicas que ya venían predefinidas en iptables, las cuales se llamaban input, output y forward. Estas cadenas, para este ejemplo, estarán abiertas por defecto, es decir que serán 3 cadenas vacías que no harán nada por defecto; solo existir y que dejarán que las reglas definidas dentro de éstos sean los que dictaminen los comportamientos:

Para crear la cadena llamada input, que se encargará de contener las reglas de los paquetes entrantes, haremos:

nft add chain inet filter input { type filter hook input priority 0\; policy accept\; }

Para las cadenas output y forward haríamos lo equivalente:

Output:
nft add chain inet filter output { type filter hook output priority 0\; policy accept\; }

Forward:
nft add chain inet filter forward { type filter hook forward priority 0\; policy accept\; }


REGLAS

Finalmente con todos estos preparativos creados, podemos empezar a crear nuestras reglas. Dichas reglas siempre tendrán que ir dentro de una cadena perteneciente a una tabla; de ahí todos los preparativos realizados hasta ahora.  Dichas reglas, pueden parecer algo abrumadoras al principio por las gran cantidad de posibilidades que ofrecen, pero a su favor hay que decir que son bastante intuitivas. La creación de reglas sigue esta sintaxis

nft add rule 'familia' 'tabla' 'cadena' 'expresión'

Inicialmente todo estaría claro a excepción de la expresión en sí, que sería lo que definiría la regla. Las expresiones son unas reglas que tienen que coincidir bajo ciertas circunstancias y que tras las cuales se deciden ciertas acciones. Esto dicho así puede parecer lioso, pero al final sería definir la regla, su argumento y la acción que se realizará al respecto... Es mejor empezar con un ejemplo sencillo que definiría la regla más sencilla posible; vamos a crear una regla que impida que puedan acceder al puerto 80. La regla se añadiría tal que así:

nft add rule inet filter input tcp dport 80 drop

En esta regla estaríamos diciendo que todo el tráfico TCP al puerto 80 sería bloqueado, y como podéis observar la expresión en sí es intuitiva. Existen muchísimas expresiones y reglas, y aquí sería imposible abarcar todas, pero las más comunes serían:

oifname 'nombre de la interfaz SALIENTE'
iifname 'nombre de la interfaz ENTRANTE'

ip protocol 'protocolo'
ip daddr 'direccion IPv4 de DESTINO'
ip saddr 'direccion IPv4 de ORIGEN'

ip6 daddr 'direccion IPv6 de DESTINO'
ip6 saddr 'direccion IPv6 de ORIGEN'

tcp dport 'puerto de DESTINO'
tcp sport 'puerto de ORIGEN'

udp dport 'puerto de DESTINO'
udp sport 'puerto de ORIGEN'

ct state 'new | established | related | invalid'

Dichas expresiones pueden combinarse entre sí dentro de la misma regla y siempre tienen que terminar con una política; las más comunes son las mencionadas antes: accept y drop. Pero existen también las políticas queue, continue y return; además de una política especial, la cual solamente se puede usar en las cadenas de tipo nat, llamada masquerade. Esta última lo que haría sería transformar la IP de origen del tráfico saliente en la IP de dicha interfaz, lo cual es común en las labores de NATeo, pues lo que se hace es transformar una IP en otra.

Usando lo de arriba como referencia podemos hacer combinaciones como estas:

Bloquear todo el trafico al puerto 22 desde el rango de IPs 192.168.1.0/24:
nft add rule inet filter input tcp dport 22 ip saddr 192.168.1.0/24 drop

Bloquear todo el trafico entrante nuevo (ct state new), proveniente del puerto 80. Es decir que nosotros podamos conectarnos a Internet, pero que no se puedan conectar a nuestro puerto 80 desde fuera:
nft add rule inet filter input ct state new drop

Bloquear los pings que accedan por la interfaz con nombre enp0s3:
nft add rule inet filter input iifname enp0s3 ip protocol icmp drop


Esto solo sería una parte de lo que puede hacer nftables, pero nos sirve para hacernos una idea global de la potencia que nos puede ofrecer esta utilidad.

Para listar todo aquello que hemos creado (las tablas, cadenas y reglas) tenemos el comando:
nft list ruleset

El cual nos mostrará nuestra configuración completa; configuración que podemos volcar en el fichero de configuración de nftables con el fin de que sea permanente. Esto se puede hacer a mano o mediante el comando:
nft list ruleset > /etc/nftables.conf

En caso de querer eliminar una regla que hayamos creado, es importante saber que, de momento, no es tan sencillo como sustituir nft add por nft delete; desgraciadamente, es necesario ejecutar primero el comando:
nft list ruleset -a

Allí veremos que al lado de cada tabla y cada regla aparecerá: #handle, seguido de un número; para eliminar la regla, tendremos que hacer referencia al handle con dicho numero. Si por ejemplo la regla de inet filter tuviese el handle 7, tendríamos que escribir:
nft delete rule inet filter input handle 7

Esto último no es del todo intuitivo y lo ideal sería poder eliminarlo de forma "natural", pero de momento es posible.


En definitiva, nos encontramos ante una versión más potente e intuitiva que iptables, que si bien ofrece varias ventajas, también posee un par de desventajas. El hecho de tener que conocer el handle de la regla para poder eliminarla, no es del todo afinado, al igual que la incapacidad de poder usar la familia inet para la tabla nat, o que sea necesario crear la tabla nat junto con sus correspondientes cadenas desde cero para hacer un simple 'masquerade' del tráfico postrouting.

Aún así es recomendable acostumbrarse a utilizarla, pues Debian 10 ya no usa iptables y en un futuro cercano nos veremos obligados a utilizar este firewall en el resto de distribuciones. Además, seguramente con el paso del tiempo irá puliendo esos pequeños detalles que hacen que esta potente herramienta no sea del todo perfecta.

Espero que os haya resultado útil.

Saludos.

martes, 17 de abril de 2018

Hotlinking; qué es y como evitarlo en Apache 2

Todos aquellos que tienen un servidor web expuesto al público, saben que al hacerlo dejan dicho servidor expuesto al mundo, y aún con un firewall bien configurado para evitar, en su medida, ciertos ataques, saben que siempre se corre riesgo de que por un motivo u otro, la web deje de estar disponible, su tiempo de respuesta sea lento o que ésta sea vulnerada. Teniendo en cuenta que el objetivo de una web es que "todos" la vean, es harto difícil lograr combinar una seguridad "infranqueable" y disponibilidad, y lo peor de todo es que a veces, acciones insignificantes que no son malintencionadas, pueden afectar al rendimiento de nuestra web... Hoy quiero hablaros de dicho último en especial; concretamente de una acción llamada hotlinking.

hotlink_portada

El hotlinking es una acción que si bien en sí no es maligna, puede perjudicar a otros en determinados aspectos, pues se trata de el uso de imágenes de otros servidores en vez de imágenes propias para enriquecer el contenido de una web. A modo de ejemplo, supongamos que queremos añadir una imagen a nuestra web; tenemos dos opciones, o subirla a nuestro servidor, o hacer referencia a la URL de una imagen ya hospedada en otro servidor; la segunda opción se trataría de un hotlink. Esto en sí no es un problema cuando se tratan de pocas imágenes y pocos links... Pero sí que puede ser problemático cuando el número de hotlinks es muy alto; especialmente si las páginas desde las que se reciben los hotlinks son muy visitadas, pues cada vez que dicha imagen es cargada en la otra página, estaría consumiendo ancho de banda de nuestro servidor, ya que la imagen que estarían solicitando estaría alojada en nuestro servidor, con lo que en verdad nos estarían haciendo una solicitud de imagen a nosotros y no a ellos.

Con el fin de que el ancho de banda de nuestra web no sea consumido involuntariamente, lo ideal es protegernos del hotlinking; lo cual afortunadamente es sencillo de implementar en Apache 2. Para ello hay dos tipos de prevención de hotlinking; aquel que directamente te pone muestra una imagen nula o aquel que te muestra una imagen concreta (y diferente) con el fin de dar a entender que están realizando una práctica no deseada contra nuestras imágenes.

Para poder aplicar dicha medida de protección en nuestro servidor, lo primero que necesitamos hacer es tener el módulo mod_rewrite activado en nuestro servidor web Apache2. Dicho módulo es instalado por defecto con Apache2, pero al mismo tiempo se encuentra desactivado por defecto, con lo que primero activaríamos dicho módulo, lo cual es tan sencillo como escribir el comando de a continuación como root:
a2enmod rewrite 
Veremos que nos solicita reiniciar Apache2 con el fin de hacer efectivo el cambio, pero todavía no lo haremos debido a que necesitaremos hacer un pequeño cambio en la configuración de este servicio para que pueda trabajar con el módulo rewrite... Esto es debido a que Apache2 por defecto está diseñado para no trabajar con dicho módulo y para no permitir que se "sobrescriban" las políticas del servidor web. En este caso, al querer modificar el comportamiento del servidor para prevenir el hotlinking, editaremos el fichero /etc/apache2/apache2.conf; teniendo en cuenta que lo más común es que la página web esté alojada en /var/www/ (o en uno de sus subdirectorios), cambiaremos lo siguiente:

Antes:
<Directory /var/www/>
        Options Indexes FollowSymLinks
        AllowOverride none
        Require all granted
</Directory>

Despues:
<Directory /var/www/>
        Options Indexes FollowSymLinks
        AllowOverride all
        Require all granted
</Directory>

Con dicho cambio realizado, ahora sí que procederíamos a reiniciar Apache2 mediante el comando:
service apache2 restart
Una vez tengamos los preparativo realizados, pasaremos a implantar nuestra protección contra hotlinks, lo cual lograremos gracias a la intervención de un fichero que crearemos llamado .htaccess, cuya función es rescribir la configuración usada para el servicio web dentro del directorio en el que se aloja ésta y, también, dentro de los subdirectorios de la susodicha. En mi caso en concreto la web se encontraría alojada en /var/www/html, web en la cual estaría hospedada la siguiente imagen:

no_hotlink_prevent

Dicha imagen se encontraría desnuda en estos momentos, es decir que podría ser accedida desde cualquier otra web, con lo que dentro del directorio /var/www/html crearíamos el fichero .htaccess con el siguiente contenido:

RewriteEngine on
RewriteOptions InheritDown
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)://(www\.)?192.168.1.8/.*$ [NC]
RewriteRule \.(jpg|jpeg|png|gif)$ - [NC]

Desgranemos cada línea con el fin de entender el contenido del fichero y no hacer un simple copia-pega.

La primera línea, RewriteEngine on; habilita la posibilidad de realizar las opciones "rewrite" que se ejecutan a continuación, acciones realizadas gracias al módulo rewrite de Apache2; en caso de carecer de dicha línea o tener dicho valor establecido a off.

La segunda línea, RewriteOptions InheritDown, la cual es opcional, sirve para que los subdirectorios hereden la configuración aplicada en dicho .htaccess.

La tercera y cuarta línea, son las condiciones bajo las cuales se ejecutaría el rewrite. En ambas se tiene en cuenta qué IP o dominio va a hacer referencia a la web debido a que en la condición, RewriteCond, se revisa dicho valor gracias a %{HTTP_REFERER}, después del cual se dice desde donde se realiza una petición HTTP al servidor. Dicha petición se realizaría desde dos orígenes, desde el propio servidor (a nivel interno) para lo cual pondríamos el parámetro en cuestión vacío, lo cual se representa como: !^$. En cambio, para especificar nuestro host, tendríamos que escribir el nombre (o la IP) de éste teniendo en cuenta que se puede hacer referencia al host como http, https (si lo tenemos habilitado), con www o sin este. En mi caso el servidor Apache2 sería la IP 192.168.1.8. Además, veremos que al lado hay un parámetro llamado [NC]; dicho parámetro se encargaría de no hacer distinción entre mayúsculas y minúsculas.

Por último se pondría la re-escritura de "reglas" mediante el RewriteRule, el cual en este caso haría que todas las peticiones que HTTP que se hagan a las imágenes jpg,jpeg,png y gif, sean bloqueadas. Por ejemplo, si hacemos una petición a dicha imagen desde otro servidor web, veremos una imagen en blanco:


hotlink_block
Esto nos serviría para bloquear el hotlinking desde otros sitios; si deseásemos que se mostrase una imagen concreta que fuese indicativa de que tenemos la protección contra hotlinks activada, podríamos editar el contenido anterior para que en la línea RewriteRule nos redirija a una imagen local previamente preparada. La re-dirección la haríamos especificando la ruta local de dicha imagen.

RewriteEngine on
RewriteOptions InheritDown
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?192.168.1.8/.*$ [NC]
RewriteRule \.(jpg|png)$ /var/www/html/imagenes/candado.png [NC]

Ahora en caso de intentar acceder a la imagen desde un origen no grato, veríamos la imagen de un candado tal y como podemos ver en la siguiente captura:

hotlink_redirect

Esta medida puede ser incluso más efectiva que la del bloqueo, ya que sería claramente disuasoria de que las personas intenten hacer hotlinks a dichas imágenes propias y que en caso de desear mostrarlas, tengan la necesidad de descargárselas y subírselas a sus propios servidores.

Como podéis ver la técnica de prevención de hotlinks es fácil y sencilla de aplicar, medida que si bien puede uno pensar que no necesita, puede prevenirle a uno del consumo indeseado de ancho de banda; prevención que se puede aplicar de una forma muy rápida como se ha podido ver aquí.

Espero que os haya resultado útil.

Saludos.

viernes, 23 de marzo de 2018

Cómo habilitar el tráfico PPTP a través de un router Linux

La creación de un router "casero" con Linux es relativamente sencillo; solamente necesitamos dos tarjetas de red y tener claras las IPs y VLANes a la que pertenece cada interfaz de red... La cuestión está en que a veces podemos tener problemas de comunicación con ciertos servicios al "aislarnos" gracias a dicho router casero que hemos creado con nuestro sistema Linux. Dicho aislamiento puede deberse a veces a problemas de configuración con iptables, o a que debido a algunas políticas por defecto adoptadas por Linux, cierto tráfico es bloqueado. En este caso quiero mostraros como habilitar el tráfico PPTP (Point to Point Tunelling Protocol) en Linux.

pptp_linux

Podemos tener una configuración perfecta en el cortafuegos, pero aún así ver que el tráfico no está llegando correctamente a su destino... Esto es debido a que Linux tiene deshabilitado por defecto el enrutamiento del tráfico PPTP, ya que hoy en día es considerado inseguro y es mucho más recomendado usar tecnologías tales como OpenVPN o tecnologías que usen Ipsec. Aún así, no siempre podemos trabajar en las circunstancias ideales y cuando nos piden conectarnos a un servidor VPN ajeno, no podemos elegir qué tipo de VPN es, sino que tenemos que adaptarnos a las circunstancias. Es por ello que tendremos que habilitar que dicho tráfico "fluya" por nuestro router.

Afortunadamente la solución es sencilla; lo primero de todo sería comprobar si tenemos el módulo el enrutamiento (también conocido como nateo) del protocolo PPTP activado. Esto es tan sencillo como listar todos los módulos existentes, haciendo un filtrado del módulo que buscamos, que en este caso sería nf_nat_pptp. Dicho listado lo haríamos gracias al comando lsmod:
lsmod |grep nf_nat_pptp
Lo más normal sería que el comando nos diese un resultado vacío; es decir que el módulo no estuviese activo. Afortunadamente la solución es extremadamente sencilla: Para insertar el módulo habría que ejecutar el comando:
insmod nf_nat_pptp
Gracias a dicho comando tendríamos activado el módulo en cuestión, si bien para que este cambio fuese permanente habría que incluirlo en el arranque añadiéndolo en al fichero /etc/modules. Para ello habría que escribir el comando:
echo 'nf_nat_pptp' >> /etc/modules
Ahora bien, con dicho comando no sería suficiente, habría que hacer que el kernel también fuese capaz de hacer las acciones necesarias para gestionar dicho tráfico. Afortunadamente el cambio solamente consistiría en añadir una línea al fichero /etc/sysctl.conf. Dicha línea sería añadida tal que así:
echo 'net.netfilter.nf_conntrack_helper=1' \ 
>> /etc/sysctl.conf
Para aplicara los cambios dentro de dicho fichero simplemente habría que ejecutar el comando:
sysctl -p
Gracias a este cambio, un sistema Linux que actúe como enrutador, enrutaría también el tráfico PPTP, brindándonos así la posibilidad de conectarnos a dichos tipos de VPN.

Espero que os haya sido útil.

Saludos.

miércoles, 21 de marzo de 2018

Límites en Linux; qué son y cómo controlarlos

A la hora de trabajar con servidores Linux, la prioridad de uno suele ser siempre la misma: Que sea capaz de dar servicio todo el tiempo posible y que sea capaz de atender cualquier petición que se le realice. Ambas necesidades tienen una estrecha relación con el hardware instalado, pero en muchas ocasiones se ignora el software, el cual también tiene un papel importante. Podemos tener un hardware extremadamente potente que si a nivel de software no tenemos la optimizaciones necesarias, no le estaremos sacando partido al susodicho debido a que tenemos unos límites demasiado estrictos; es por ello que hoy quiero hablaros sobre los límites en Linux.

limits_portada

Existen ciertas aplicaciones tales como las bases de datos y las aplicaciones web, que requieren abrir una ingente cantidad de ficheros: Ficheros temporales, bases de datos, ficheros de configuración, etc... Además, con las bases de datos podemos estar haciendo varias consultas o "aperturas" de fichero simultáneas que contarían como múltiples aperturas de fichero... Esto en servidores con una carga de trabajo relativamente baja no supone un problema, pero en servidores con altas cargas de trabajo sí que supondría un problema ya que podríamos superar el límite de ficheros abiertos de forma simultánea, dando como error interno el mensaje: "Too many open files". Esto es debido a que los límites impuestos por el sistema nos impiden abrir más ficheros, al igual que otros límites nos pueden impedir otras tareas.

Afortunadamente dichos límites pueden ampliarse de forma sencilla. Lo primero sería conocer nuestro límite actual, lo cual es tan sencillo como escribir el comando:
ulimit -n
En caso de tener los valores por defecto, el valor mostrado por la salida de dicho comando sería de 1024; es decir que el límite actual sería de 1024 ficheros abiertos. Esto puede parecer un valor muy alto, pero en un servidor dicho valor puede quedarse corto, especialmente si trabajamos con bases de datos como PostgreSQL que trabaja con una gran cantidad e ficheros temporales por cuestiones de rendimiento.

Para cambiar el límite actual de forma provisional, podemos recurrir al comando:
ulimit -n 99999
El problema de dicho comando sería que el límite solo valdría para el usuario y sesión actual; si cerramos sesión o reiniciamos el equipo, dicho límite se perdería y volvería a establecerse el de 1024. Para realizar un cambio más permanente tendríamos que editar el fichero /etc/security/limits.conf.

Dicho fichero establece los límites para diferentes usuarios y grupos. Por defecto su contenido está completamente comentado, con lo que cualquier límite que deseemos agregar tendrá que ser hecho a mano. Antes de añadir cualquier contenido, es importante entender su sintaxis, ya que será lo que nos ayudará a entender qué queremos añadir y cómo hacerlo. Cada límite que queramos añadir estará compuesto por cuatro secciones separadas por espacios entre sí; en concreto la estructura sería:

dominio tipo objeto valor


  • Dominio: Este valor es el que dictamina a qué usuario o grupo vamos a asignarle el límite. Con * se haría referencia a todos.
  • Tipo: Se puede elegir un límite duro (hard) o blando (soft). El blando sería el límite "por defecto" que se tendría en el sistema, mientras que el duro sería el límite que no se podría traspasar aún asignándoselo con el comando ulimit -n X. 
  • Objeto: El objeto especificaría a qué le deseamos poner el límite; se puede poner límite al número de "logueos" simultáneos con el mismo usuario con maxlogins, también se puede poner un límite para el número de procesos controlados por un usuario o grupo mediante nproc, o también puede establecerse el límite de ficheros abiertos mediante nofile. Existen otros objetos tales como data o fsize que establecerían los límites de tamaño de los datos y de los archivos respectivamente... Hay dos objetos cuyo límite es delicado y que es recomendable modificar con cuidado; dichos objetos serían nice; que indicaría el valor máximo de prioridad "nice" que se puede establecer a un proceso, y priority que establecería la prioridad por defecto asignada al programa ejecutado por el usuario o grupo. Ambos objetos pueden tener un valor negativo, pues la prioridad oscila entre -20 y 19 siendo -20 la prioridad más alta y 19 la más baja. Existen más objetos, pero los mencionados serían los más populares.
  • Valor: El valor sería simplemente el indicador del límite. Aquí se puede poner el valor que nosotros veamos necesario; se podría poner un valor bajo en algunos objetos tales como maxlogins, mientras que se podrían poner valores altos (pero definidos) para objetos tales como nofile. En caso de querer no ponerle limitador alguno se le pondría el valor -1, valor que haría que el límite fuese "infinito" ; la excepción sería para los objetos nice y priority, pues para ambos el valor -1 es un valor que se encuentra dentro del rango que manejan y carecen de ningún valor "infinito".

A sabiendas de cual es la estructura de un límite, vamos a plasmar un par de ejemplos:

Uno de los límites más "usados" sería el la cantidad de ficheros abiertos simultáneos, el cual, tal y como hemos visto antes se especificaría con el objeto nofile. Podemos crear un límite "duro" y uno "blando" para el usuario que, generalmente, más ficheros abrirá: El usuario root. Podemos poner un límite "blando" de 9999 ficheros y uno duro de 99999, lo cual se haría añadiendo lo siguiente:

root   soft   nofile  9999
root   hard   nofile  99999

Por otro lado, en caso de querer poner un límite de maximos logins simultáneos podemos hacer:

root   soft   maxlogins 4
root   hard   maxlogins 4

En caso de querer hacer referencia a un grupo en vez de a un usuario la sintaxis sería @nombre_grupo. Es decir que si deseásemos hacer que el número de procesos controlados por cualquier miembro del grupo usuarios, fuese infinito, haríamos tal que así:

@usuarios soft  nproc -1
@usuarios hard  nproc -1

Para que luego estos límites hagan efecto simplemente valdría con reiniciar el equipo o (en caso de que fuese con un usuario que no fuese root) cerrar sesión, pues las sesiones activas mantendrían los valores actuales.

Espero que os haya resultado útil.

Saludos.

martes, 24 de octubre de 2017

Cómo emular comportamientos de red en Linux con Net Emulation

Tras una buena temporada sin escribir, por fin vuelvo con las pilas cargadas y con un artículo que, en mi opinión puede serle muy útil a muchos. En la ocasión de hoy quiero poneros en un situación hipotética. Tenemos un equipo con un sistema operativo Linux (no importa que sea Debian o Red Hat) con el que queremos emular comportamientos "extraños" de red... Lo normal, y deseado, es que una red esté correctamente gestionada, que el tráfico de red fluya con fluidez, que todos los elementos de la red se comuniquen entre sí sin problemas, etc... Esto es lo deseable, pero no siempre lo que ocurre debido a un sin fin de factores, entre los cuales se encontraría, por supuesto, el factor humano. La cuestión está en que a veces, la mejor forma de resolver el problema, es emulándolo primero para después ver cómo solventarlo, y he ahí donde entra en juego la herramienta tc (Traffic Controller); más concretamente uno de sus módulos llamado netem, más conocido como Net Emulation.

Tux_Net_Emulation

Net Emulation permite crear situaciones que nos permiten emular ciertos comportamientos indeseados, tales como retardos, paquetes erróneos, duplicidades, etc... Es decir que nos permite crear situaciones indeseadas de forma controlada con el fin analizar posibles reacciones por ciertos equipos ante dichas situaciones. Tanto la herramienta Traffic Control como el módulo netem vienen por defecto incluidos en Linux, pues ambos vienen incluidos por defecto con la paquetería de iproute2 con lo que afortunadamente no requieren instalación alguna. 

El uso de este módulo en sí es bastante sencillo, si bien es importante conocer la estructura general que es necesaria conocer:

tc qdisc acción dev nombre_interfaz usuario netem acción_netem

Aquí podemos ver cuatro partes en cursiva, que serían las que variarían dependiendo de nuestras necesidades, cada parte tendría el siguiente significado:

  • Acción: Cuando escribimos el comando siempre hay que especificar si se va a añadir un comportamiento personalizado, si se va a modificar o eliminar. Es decir que en esta parte podemos optar por hacer: add, change o del. Es importante tener en cuenta que una vez añadido una emulación a la interfaz de red, no podremos hacer otro add, sino que tendremos que hacer un change para modificarla o un del para eliminarla.
  • Nombre_interfaz: Simplemente le decimos sobre qué interfaz de red queremos aplicar la emulación de red.
  • Usuario: El usuario que realizará el cambio de comportamiento. Por lo general siempre será root.
  • Comportamiento: Finalmente diríamos que comportamiento queremos emular; es decir qué emulación de red queremos hacer. Esta parte al ser algo extensa la explicaré con más detalle más adelante.

Teniendo clara esta estructura base, podemos empezar a realizar las primeras emulaciones de red.

Comenzaremos con una emulación muy sencilla pero muy útil, que es la de la implantación de retardos. Esto hace que cualquier interacción realizada con esta interfaz tardará un tiempo extra en ser realizada. Esto se logra gracias al comportamiento delay, cuyo comando completo sería:

tc qdisc acción dev nombre_interfaz usuario netem delay retardo_en_milisegundos

He aquí un comando a modo de ejemplo en el que vamos a añadirle un retardo de 200 ms a la interfaz de red eth0, con el usuario root:

tc qdisc add dev eth0 root netem delay 200ms

Una forma muy fácil de comprobar el efecto de este cambio es haciéndole un simple ping a la IP de dicha interfaz de red, tal y como podéis ver en la siguiente imagen:

delay_1

Además de poner un retardo de Xms, podemos también hacer que dicho valor no siempre sea fijo, sino que oscile entre ese valor y Xms arriba o abajo de forma aleatoria. Por ejemplo si pusiésemos el mismo comando de antes con una oscilación de 10ms, la latencia del ping podría ser hasta 10ms mayor o menor.  He aquí el comando que haría referencia a exactamente dicho ejemplo:

tc qdisc add dev eth0 root netem delay 200ms 10ms

En la imagen de a continuación podemos apreciar esa oscilación:

delay_2

Obviamente podemos hacer más cosas aparte de crear retardos; otra funcionalidad muy útil de este módulo sería la de la posibilidad de que los paquetes recibidos se consideren como "perdidos", es decir que hayan paquetes que no hayan llegado a su destino. Para ello, en vez de recurrir al comportamiento delay recurriremos a loss, comportamiento en el que especificaremos qué % de paquetes queremos que se "pierdan". Por ejemplo podemos hacer que la mitad de los paquetes no lleguen a su destino, para lo cual el comando sería el siguiente:

tc qdisc add dev eth0 root netem loss 50%

Al igual que antes, con un simple ping también podemos verificar que ahora alrededor de la mitad de los paquetes enviados se perderán; he aquí una pequeña muestra a modo de ejemplo:

loss

Casi tan grave como la perdida de paquetes es la duplicidad de éstos, cosa que afortunadamente también es emulable en Linux. Dicha emulación es posible gracias al comportamiento duplicate y usa la misma sintaxis que el anterior comando, sustituyendo, obviamente, loss por duplicate.

tc qdisc add dev eth0 root netem duplicate 50%

En este caso algunos de los pings que mandemos al equipo recibirán como respuesta que hay una duplicidad; es decir que respondería como si hubiesen dos equipos con la misma IP en la misma VLAN. Dichos pings con respuesta de duplicidad en la red tendrían la etiqueta DUP!, tal y como se puede ver en la siguiente captura:

duplicate

Otro problema que puede surgir en una red es que los paquetes de red se encuentren corruptos, cosa que también podemos emular gracias corrupt que tiene la misma sintaxis que el anterior comando, sustituyendo duplicate por corrupt.

tc qdisc add dev eth0 root netem corrupt 50%

En este caso, la respuesta que recibiremos al hacerle ping será que se esperaba un valor determinado pero que han recibido uno diferente al que se debía, mostrándonos algo como lo de la captura mostrada aquí abajo:

corrupt

Estas serían las diferentes emulaciones que se pueden hacer gracias a esta herramienta; emulaciones que, en mi opinión, no son pocas y pueden ser de gran ayuda a la hora de intentar reproducir problemas reales para después encontrarles solución. La potencia de el módulo Net Emulation queda patente ya que es increíblemente flexible y versátil. Obviamente las funciones pueden combinarse; es decir que se puede hacer que haya un delay determinado, con un % determinado de paquetes erróneos otro % determinado de paquetes duplicados, etc... Por ejemplo, podemos querer editar una de las reglas que hemos creado atrás para que tenga toda esta combinación de comportamientos; con lo que en vez de usar add, usaremos change para obtener el siguiente comando:

tc qdisc change dev eth0 root netem delay 100ms 20ms \
loss 1% duplicate 0.5% 

Como podéis observar, el comando no es más que una combinación de los atrás vistos, con el cual se puede combinar una latencia alta con un pequeño porcentaje de paquetes perdidos y uno aun menor de duplicados. Un detalle importante a la hora de hacer uso de la función change; si nos fijamos en el valor anterior, se hace un change a los valores delay, loss y duplicate. Si anteriormente hubiese sido especificado un valor para corrupt, la acción change no modificaría su valor ni lo eliminaría a menos que se especificase específicamente. Es decir que si por ejemplo hubiésemos hecho un corrupt del 50% y luego hubiésemos introducido este comando, el valor de corrupt sería siendo el mismo.

Finalmente, para eliminar estos comportamientos especiales por completo, podemos recurrir a la acción del, para lo cual simplemente habría que escribir:

tc qdisc del dev eth0 root netem

Tal y como se puede ver en este artículo, la emulación de diferentes situaciones "conflictivas" es más sencillo de lo que parece, y afortunadamente, todo ello se puede hacer desde cualquier equipo con Linux instalado y sin herramienta especial alguna, estando dicha emulación al alcance de todo el mundo.

Espero que os haya resultado útil.

Saludos.

martes, 1 de agosto de 2017

Predictable Network Interface Names: Qué es y cómo deshabilitarlo

La tecnología va evolucionando constantemente y siempre en cada versión de cada sistema operativo, se van apreciando cambios; cambios que pueden ser desde parches de seguridad a otros más "tangibles" tales como nuevas versiones de software, cambios en el init (el famoso systemd) o pequeños, pero en parte importantes, cambios en la nomenclatura, tales como los realizados en las interfaces de red. Cualquiera que haya estado usando GNU/Linux durante años sabe que "normalmente", a la hora de llamar a una interfaz de red, se le llamaba eth0, eth1, etc... o en caso de ser una tarjeta de red inalámbrica, se le llamaba wlan0, wlan1, etc... La cuestión está que esa nomenclatura ya no se mantiene y las interfaces de red reciben un nombre distinto, dicha nomenclatura no era del todo fiable ni robusta...

PNIN_portada

La explicación técnica sería que si bien los nombre usados antiguamente era fáciles de recordar, la "relación" entre el nombre de la interfaz de red y la MAC no siempre era del todo fiable, pues dicha MAC podía cambiar (en un entorno virtualizado es algo relativamente común), y a veces debido a problemas con drivers podía haber problemas. Para solucionar dicho problema, desde systemd han creado la funcionalidad: Predictable Network Interface Names.

Dicho tipo de nomenclatura se basa en nombrar las interfaces de red basado en su firmware, el tipo de interfaz y su MAC, haciendo que el proceso sea completamente automático y que se evite cualquier tipo de conflicto con los nombres y/o MACs, con el fin de evitar duplicidades y/o problemas de configuración con las interfaces de red... Este nuevo tipo de interfaces tienen 3 tipos de prefijos, seguidos de unas letras y números:

  • en: Este prefijo significaría que la interfaz de red es del tipo Ethernet (LAN)
  • wl: En este caso se haría referencia a un interfaz del tipo inalámbrica (WLAN).
  • ww: Aquí se haría referencia a una interfaz de red de área amplia inalámbrica (WWAN)

Hasta aquí la parte que más fácil se puede recordar, pues a partir de aquí la nomenclatura se torna bastante peculiar, y si bien es una nomenclatura "predictiva" que el sistema puede detectar y reconocer correctamente, a nivel humano no es, ni de lejos, tan predecible. Esta funcionalidad intentará ejecutar una serie de políticas para nombrar la interfaz de red, primero intentará una política y en caso de no poder aplicarla lo intentará con la siguiente y así sucesivamente... Las políticas a aplicar (en orden) serían:

  • Política 1: Se intentará incorporar al nombre de la interfaz, la letra o más el número de indexación que le ha dado la BIOS/firmware para los elementos integrados en la placa. Por ejemplo: eno33. Si la tarjeta de red no fuese integrada, no fuese reconocida como tal o simplemente no se pudiese aplicar dicha política, se pasaría a la política 2.
  • Política 2: Se intentará incorporar al nombre de la interfaz, la letra s más el número de indexación que le ha dado la BIOS/firmware para los elementos hotplug. Por ejemplo: ens33. Si la tarjeta de red no fuese un elemento hotplug, no fuese reconocida como tal o simplemente no se pudiese aplicar dicha política, se pasaría a la política 3.
  • Política 3: Se intentará incorporar al nombre de la interfaz de red la letra p junto con la localización física ésta. Por ejemplo: enp2s0. En caso de que tampoco se pudiera, se pasaría a la política 4.
  • Política 4: Se añadirá la letra x más MAC al nombre de la interfaz; por ejemplo: enx78e7d1ea46da
  • Política 5: Si no se hubiese podido adoptar ninguna de las anteriores políticas, se usaría la nomenclatura tradicional; por ejemplo: eth0.

Como podéis ver, las nomenclaturas usadas tienen una estructura muy bien definida, pero desgraciadamente no es del todo "amigable" pues podemos encontrarnos con casos tales como la política 3 o la política 4 en los que el nombre de nuestra interfaz es largo y difícil de recordar... Esto no significa que esa desventaja haga que el uso de las políticas antiguas sea mejor, ya que generalmente las ventajas superan a las desventajas... 

El problema del uso de esta nomenclatura viene cuando tenemos multitud de scripts "antiguos", que están preparados para trabajar con los nombres de interfaz clásicos... Pues si bien es cierto que podemos ir sustituyendo los nombres mediante el comando sed... No siempre es la mejor opción, ya que basta que la Predictable Network Interface Names (PNIN para acortar), use un nombre distinto para la interfaz para que el script no funcione... Es por ello que a veces nos puede ser más beneficioso usar las nomenclaturas antiguas en nuestro sistema, si bien ¿Cómo podemos hacerlo?

Afortunadamente el cambio es muy sencillo; cambio que además puede revertirse fácilmente por si en el futuro nos hiciesen falta las nuevas nomenclaturas. Este cambio se ha aplicado en Debian 9, pero debería ser válido en cualquier sistema similar. Dicho cambio se realiza a nivel de GRUB y para ello editaremos el fichero /etc/default/grub y editaremos la línea GRUB_CMDLINE_LINUX.

Su aspecto original sería el siguiente:
GRUB_CMDLINE_LINUX=""

Dicha línea debería ser editada para que tenga el siguiente aspecto:
GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0"

Con esto haríamos que tan pronto como se cargue el GRUB, la asignación del nombre se realice a nivel de kernel y con mediante PNIN, si bien para aplicar los cambios tendríamos que ejecutar dos comandos:
sudo grub-mkconfig
sudo update-grub

Ahora bien, antes de reiniciar el sistema sería necesario entrar sí o sí dentro del fichero /etc/network/interfaces para cambiar las nomenclaturas a las interfaces, pues en caso contrario la interfaz de red en cuestión, cuando obtuviese el "nuevo" nombre, no podría asociarse a una IP. Esto lo podemos hacer o bien a mano o bien mediante el comando sed, aunque para esto último tendríamos que tener muy claros los nombres. Supongamos que tenemos una sola interfaz de red en el sistema, llamada ens33... Al ser la única interfaz y ser ethernet sabemos que se convertirá en eth0 con lo que podemos ejecutar el siguiente comando:
sed -i 's/ens33/eth0/g' /etc/network/interfaces

Por último, pero no por ello menos importante, sería necesario reiniciar, con el fin de poder aplicar la nueva configuración introducida en el GRUB y poder hacer referencia a nuestra interfaz tal y cómo siempre hemos hecho.

Espero que os haya resultado útil.

Saludos.

miércoles, 26 de julio de 2017

Conociendo iproute en Linux

Finalmente el uso del comando ip se ha vuelto una necesidad; hace muchos años se lleva diciendo que el comando ip iba a sustituir al famoso ifconfig, entre otros, pero siempre ha habido gente que conociendo el archi-conocido comando, no necesitaba ahondar más y recurrir a su "primo" iproute (que contiene el comando ip, entre otros) para manipular la configuración de red en Linux. La cuestión es que ahora las nuevas versiones, tales como Debian 9, ya no usan el comando ifconfig, con lo que lo que antes era cuestión de gustos, ahora se ha vuelto necesario aprender a usar. En su momento expliqué las ventajas del comando ip para la manipulación de la tabla ARP, pero ahora es necesario dar un paso más y dominarlo un poco más a fondo para que, al menos, podamos defendernos con iproute, concretamente con el comando ip.

iproute_portada

El comando ip agrupa una serie de "subcomandos" que pueden controlar desde la propia IP, valga la redundancia, hasta otros factores relacionados con ésta, tales como la tabla ARP, la conectividad y la puerta de enlace. Englobar todos los parámetros de todas las opciones es una tarea prácticamente imposible, con lo que nos centraremos en aquellas opciones y/o comandos que, en mi opinión, son los más útiles e importantes en el día a día, pues serán los que más posibilidades tienen de ser usados.

Empecemos con el comando más básico e importante de todos, el comando: el comando ip addr. Este comando sería el equivalente al clásico ifconfig y es sin lugar a dudas el que más probabilidades tiene de ser usado. Dicho comando tiene diferentes opciones que permitirán tanto mostrar como modificar y/o eliminar nuestra ip actual. Veamos cómo hacerlo:

Para mostrar nuestra IP podemos usar uno de los siguientes comandos:
ip addr
ip addr show
ip addr show dev ens33

Los dos primeros comandos mostrarían la IP de todas las interfaces de red, mientras que el tercero mostraría la IP de la interfaz con nombre ens33 (algo equivalente a hacer un ifconfig de una interfaz de red concreta).

Obviamente podemos hacer más cosas con este comando, tales como la asignación o eliminación de IP a una interfaz de red, cosa tan sencilla como hacer:
ip addr add 192.168.1.2/24 dev ens33
ip addr del 192.168.1.2/24 dev ens33

Otra funcionalidad muy útil sería la manipulación de la interfaz de red en sí; es decir la activación y desactivación de la interfaz de red o la activación y desactivación de algunas características de dicha interfaz... Dicha funcionalidad se denominaría ip link, y con ella podríamos hacer cosas tan interesantes como las siguientes:

Activación de la interfaz de red ens33:
ip link set dev ens33 up

Desactivación de la interfaz de red ens33:
ip link set dev ens33 down

Obviamente podemos manipular más características de la interfaz de red... No todas son usadas habitualmente pero hay algunas que nos pueden resultar realmente interesantes:

Activación/Desactivación de modo promiscuo en interfaz de red ens33:
ip link set dev ens33 promisc on
ip link set dev ens33 promisc off

Activación/Desactivación del arp en la interfaz de red ens33:
ip link set dev ens33 arp on
ip link set dev ens33 arp off

Activación/Desactivación de la gestión del tráfico multicast en la interfaz ens33;
ip link set dev ens33 multicast on
ip link set dev ens33 multicast off

También podemos usar la herramienta ip link para añadir interfaces de red virtuales para luego asignarles una ip y activarlas... Obviamente dichas interfaces virtuales también pueden ser eliminadas. Esto requiere una combinación de las utilidades ip link e ip addr, pero el proceso es relativamente sencillo:

Para crear una interfaz de red virtual plenamente funcional, lo primero que haremos será crear dicha interfaz virtual. Al ser una interfaz virtual, ésta dependerá de una interfaz física (en este caso ens33):
ip link add link ens33 name ens33.1 type vlan id 100

Luego únicamente habría que asignarle una dirección IP a dicha intefaz, con nombre ens33.1, y activarla, cosa que ya hemos visto antes y que sería tan sencillo como hacer:
ip addr add 192.168.1.10/24 dev ens33.1
ip link set dev ens33.1 up

Por último podemos también eliminar las interfaces de red que hayamos creado mediante este método, mediante el comando:
ip link delete ens33.1 

No podríamos repasar el comando ip sin mencionar la definición de puertas de enlace mediante el comando ip route. Lo primero que tendríamos que conocer de dicho comando sería la tabla de enrutamientos que se tiene actualmente, lo cual se puede hacer de dos formas:
ip route 
ip route show

Además de dicho listado, también podemos usar el comando ip route para denegar una IP de forma parecida como haríamos con iptables; si bien esta utilidad tiene muchísimas más limitaciones que iptables. Podemos denegar el acceso a una IP de forma simple o también podemos especificar de qué IP denegar el acceso a otra IP. Por ejemplo:

Para denegar el acceso a una IP:
ip route add prohibit 192.168.1.1

Para denegar el acceso a una IP desde una IP de origen determinada:
ip route add prohibit 192.168.1.1 from 192.168.1.2

Además de estas dos funcionalidades, tendríamos la posibilidad de establecer la puerta de enlace, lo cual se puede añadir de esta forma:
ip route add default via 192.168.1.1

Para eliminar una regla añadida simplemente habría que recurrir al parámetro: del; tal y como veis a continuación:
ip route del prohibit 192.168.1.1
ip route del default via 192.168.1.1

Además de estas opciones, hay otra que si bien no especialmente utilizada a nivel de escritorio, a nivel de servidor se trata de una herramienta de un valor incalculable... Se trata de ss, el equivalente al siempre útil netstat, cuya función es listar los puertos de red del sistema. No se trata de un parámetro del comando ip y por eso lo he dejado para el final, pero se trata de una de las herramientas otorgadas por iproute que tiene un gran valor en la administración de servidores. Afortunadamente la curva de aprendizaje con esta utilidad es mínima pues el comando ss usa los mismo parámetros que netstat con lo que podremos hacer acciones como las siguientes:

Listar todas las conexiones:
ss -a

Listar todas las conexiones tcp y udp, mostrando el número de puerto en vez de el nombre correspondiente a dicho puerto.
ss -tuna

Con este conjunto de comandos (más los del manejo de arpwatch cuyo enlace se encuentra en el primer párrafo de este artículo) tendríamos un dominio global de las funcionalidades más importantes de iproute, pudiendo desenvolvernos con soltura con esta herramienta para poder manipular adecuadamente nuestra configuración de red.

Espero que os haya resultado útil.

Saludos.