Nftables, configura este firewall para Linux como un experto

Nftables, configura este firewall para Linux como un experto

Sergio De Luz

Nftables es un proyecto de netfilter que proporciona filtrado de paquetes y clasificación de paquetes en Linux. Es la evolución de iptables, y, de hecho, las reemplaza (no se puede mezclar nftables y iptables). Nftables es capaz de reemplazar en el mismo framework a iptables, ip6tables, arptables y ebtables, y todo ello bajo el mismo espacio de usuario (nft) y compatibilidad hacia atrás (con sintaxis iptables). Nftables es el framework por defecto en Debian 10, aunque no está activado por defecto ya que se sigue usando sintaxis iptables, pero por poco tiempo.

Si utilizamos el sistema Debian 10 en adelante, el framework que viene instalado por defecto es nftables, aunque tenemos la posibilidad de seguir utilizando la sintaxis iptables sin problemas, pero la «base» es la nueva nftables. Para usar la sintaxis nueva, simplemente tenemos que instalarlo desde los repositorios oficiales. Nftables es compatible con Kernel Linux 3.13 en adelante, pero es recomendable usar un Kernel 4.7 en adelante, Debian 10 usa Kernel 4.19, por lo que nos funcionará perfectamente.

El framework de iptables sufre una serie de limitaciones que se han querido mejorar con este nuevo framework:

  • Evitar duplicidad e inconsistencia en el código fuente.
  • Muchas extensiones de iptables estaban duplicadas con pequeños cambios para interactuar con diferentes protocolos.
  • Simplificar usabilidad en entornos IPv4/IPv6.
  • Mejorar actualizaciones al conjunto de reglas. Esta tarea en iptables es muy costosa y poco escalable.
  • Mejorar la sintaxis.

Principales características de nftables

Ahora nftables usa una sintaxis más compacta e intuitiva que fue inspirada por la herramienta tcpdump. Nftables proporciona una capa de compatibilidad con iptables, usando su misma sintaxis sobre la infraestructura de nftables (lo que se utiliza en Debian 10 si no se instala nft). En nftables, las tablas y cadenas son totalmente configurables, no hay tablas predefinidas que siempre deben estar, aunque no las usemos (como sí ocurre con iptables). Los nombres también pueden ser arbitrarios.

Otras características importantes de nftables, es que los “match” –m y los “target” –j desaparecen, nftables tiene expresiones. Nftables permite hacer varias acciones en una sola regla (varios targets), algo que con iptables no era posible fácilmente. Por defecto no tenemos contadores integrados en las reglas y cadenas, ahora son opcionales y pueden habilitarse si queremos. Por último, nftables proporciona una administración más sencilla para conjuntos de reglas IPv4 y IPv6, ahora no tendremos que «adaptar» las reglas de iptables a ip6tables como ocurría anteriormente.

Os recomendamos visitar la web oficial de nftables donde encontraréis todos los detalles sobre este firewall para sistemas operativos Linux.

Puesta en marcha de nftables en Debian 10

Para poner en marcha nftables en Debian 10, simplemente debemos instalar el frontend, todo lo demás ya está instalado (y se usa, aunque pongamos iptables).

sudo apt install nftables

No es necesario reiniciar el ordenador o el servidor, no se toca nada del Kernel, solamente el frontend de administración del firewall, que ahora pasa de estar en iptables, a estar con la sintaxis de nftables. Un detalle muy importante es que nftables hace una distinción entre las reglas temporales realizadas en la línea de órdenes, y aquellas otras permanentes cargadas o guardadas en un archivo.

El archivo predeterminado es /etc/nftables.conf, que ya contiene una tabla simple de cortafuegos para ipv4/ipv6 llamada “inet filter”.

La utilidad de nftables en el espacio de usuario, nft, realiza la mayor parte de la evaluación del conjunto de reglas antes de pasarlas al Kernel del sistema operativo.

En el caso de nftables, las reglas se almacenan en cadenas, que a su vez se almacenan en tablas. Para que los cambios permanezcan, debemos guardar las reglas directamente en el archivo /etc/nftables.conf. El comando que podemos utilizar para guardar estas reglas permanentemente y que se ejecuten con el reinicio del sistema, es el siguiente:

nft list ruleset > /etc/nftables.conf

A continuación, si hemos incorporado nuevas reglas manualmente, debemos reiniciar nftables para aplicar los cambios:

systemctl restart nftables.service

Todos los comandos deben ser ejecutados como administrador, ya sea con «sudo» o directamente con el usuario «root».

Funcionamiento y comandos básicos de nftables

Si queremos consultar las reglas que tenemos dadas de alta en el firewall, tendremos que poner la siguiente orden:

nft list ruleset

Las tablas en nftables alojan las cadenas, en nftables no tenemos tablas integradas como en iptables. La cantidad de tablas que tengamos y los nombres que les demos depende del usuario. Cada tabla solo tiene una familia de direcciones, y solo se aplica a los paquetes de dicha familia. Las familias pueden ser:

Familia en nftables Equivalente en iptables
ip iptables
ip6 Ip6tables
inet Iptables y ip6tables a la vez
arp Arptables
bridge ebtables

La familia predeterminada es “ip”, es la que se usará si no se especifica ninguna familia a la hora de crear la tabla. Si queremos crear una regla que se aplique tanto a redes IPv4 como IPv6, lo ideal es usar “inet” ya que es la unificación de las dos familias. ¿Dónde usar esto de inet? Si queremos filtrar por ejemplo puertos TCP/UDP es una muy buena alternativa, para evitar «duplicar» reglas en redes IPv4 y IPv6.

Un detalle importante es que inet no funciona para las cadenas “nat”, solamente para las cadenas “filter”, es decir, cuando vamos a filtrar paquetes, pero no a hacer NAT. Debemos recordar que iptables también permitía realizar Source NAT y Destination NAT, con nftables ocurre exactamente lo mismo.

Crear una tabla

La sintaxis que se utiliza para crear una tabla es la siguiente:

nft add table [familia] [nombre_tabla]

Ejemplos:

nft add table ip filtrado
nft add table inet filtrado

Listar todas las tablas, cadenas y reglas

La sintaxis que se utiliza para listar todas las tablas es la siguiente:

Nft list tables

La sintaxis que se utiliza para listar las cadenas y las reglas de una tabla en concreto:

nft list table [familia] [nombre_tabla]

Ejemplos:

nft list table ip filtrado
nft list table inet filtrado

Borrar una tabla

Si queremos borrar una tabla, antes debemos asegurarnos de que no tiene ninguna cadena, si tiene alguna cadena no dará error indicando que la tabla no está vacía.

La sintaxis para eliminar una determinada tabla es:

nft delete table [familia] [nombre_tabla]

Vaciar una tabla

Si queremos vaciar la tabla entera, podemos hacerlo fácilmente:

nft flush table [familia] [nombre_tabla]

Cadenas: qué son y cómo usarlas

Las cadenas se encargan de alojar las reglas que posteriormente debemos definir. A diferencia de las cadenas en iptables, no hay cadenas integradas en nftables. Esto significa que, si ninguna cadena utiliza ningún tipo o hook en el marco de netfilter, los paquetes de red que fluyan a través de esas cadenas no serán tocados por nftables, a diferencia de iptables. Las cadenas son de dos tipos:

  • Cadena normal: puede usarse como un objetivo de salto («jump») para una mejor organización.
  • Cadena base: punto de entrada para los paquetes de la pila de red, donde se especifica un valor de enlace. La familia es opcional, si no se especifica por defecto es “ip”.

Si queremos añadir una cadena normal, la sintaxis que debemos seguir es la siguiente:

nft add chain [familia] [ tabla] [cadena]

Si queremos añadir una cadena normal llamada “cadenaejemplo”, a la tabla “filtrado” creada anteriormente, y usamos la familia “inet” en tabla y cadena (no se pueden mezclar, da error), debemos escribir lo siguiente:

nft add table inet filtrado
nft add chain inet filtrado cadenaejemplo

Si queremos agregar una cadena base, la sintaxis que debemos utilizar es la siguiente:

nft add chain [familia] [ tabla] [cadena] { type tipo hook el_hook_que_sea priority prioridad policy política\; }
  • El “type” puede ser: filter, route o nat.
  • El “hook” puede ser:
Familia Hooks
ip/ip6/inet prerouting, input, forward, output, postrouting
arp input, output
bridge prerouting, input, forward, output, postrouting
  • Priority: es un valor entero. Las cadenas con números más bajos se procesan primero, pueden ser negativos, ideal para facilitar la gestión de las cadenas.
  • Policy: puede ser accept, drop, queue, continue o return.
nft add chain [familia] [ tabla] [cadena] { type tipo hook el_hook_que_sea priority prioridad \; }
nft add table inet filtrado
nft add chain inet filtrado cadenabase { type filter hook input priority 0\; policy accept\; }

Modificar una cadena

Lo que tenemos que hacer es llamarla por su nombre, y definir la nueva regla de “policy” que queremos cambiar: accept o drop por ejemplo. Con el ejemplo anterior, si queremos cambiar la “policy” de accept a drop:el hook de input a output:

nft chain inet filtrado cadenabase { type filter hook output priority 0\; policy drop}

Borrar una cadena

Para borrar una cadena, lo primero que debemos hacer es eliminar todas las reglas de su interior. No debe haber ninguna regla, ni ningún objetivo “jump”. Para eliminar todas las reglas de una cadena:

nft flush chain [familia] [tabla] [cadena]

Para eliminar la cadena que ya está vacía:

nft delete chain [familia] [tabla] [cadena]

Reglas: qué son y cómo crearlas

Las reglas se construyen a través de expresiones, o bien a partir de declaraciones, y están contenidas dentro de las cadenas. La utilidad iptables-translate se encarga de “traducir” las reglas iptables al formato nftables: “iptables-translate –A INPUT –j ACCEPT”.

Para añadir una regla a una cadena:

nft add rule [familia] [tabla] [cadena] handle [identificador] [declaracion]

El “handle” es opcional, e indica la posición de la regla dentro de la cadena. Si no se especifica el handle, la regla se pone al final de la cadena. Para añadir una regla a una cadena (por arriba).

nft insert rule [familia] [tabla] [cadena] handle [identificador] [declaracion]

Para eliminar una regla individual en concreto, debemos eliminarlas gracias al handle utilizado, o en la posición donde nftables la ha colocado. Para ver los identificadores de las reglas debemos listarlo:

nft –-handle list

Para eliminarla:

nft delete rule [tabla] [cadena] handle [identificador]
nft delete rule tabla input handle 10

Las reglas en nftables incluyen una expresión de coincidencia, y luego, una declaración que resuelva (si coinciden).

Las coincidencias que tenemos disponibles en nftables son:

  • meta (iif, iifname, oif, oifname): índice, nombre, de la interfaz de entrada/salida
  • icmp: type [tipo de icmp]
  • icmpv6: type [tipo de icmpv6]
  • Ip: daddr (dirección de destino), saddr (dirección de origen)
  • Ipv6: daddr (dirección de destino), saddr (dirección de origen)
  • Tcp, udp y sctp: dport y sport
  • Ct: state [new | established | related | invalid]
  • Las declaraciones resolutivas son: accept, drop, queue, continue, return, [cadena] jump y [cadena] goto.

A continuación, podéis ver un ejemplo donde bloqueamos una dirección IP de origen, y también bloqueamos tráfico TCP y UDP en un determinado puerto:

nft add table inet firewall
nft add chain inet firewall bloqueo { type filter hook input priority 0\; policy accept \; }
nft add rule inet firewall bloqueo ip saddr 192.168.1.2 counter drop
nft add rule inet firewall bloqueo ip saddr 192.168.1.3 tcp dport 80 drop
nft add rule inet firewall bloqueo ip saddr 192.168.1.3 udp dport 80 drop

Ahora vamos a crear un “ipset” con nftables, aunque lógicamente no se hace igual. Debemos recordar que IPset nos permitía crear un listado enorme de direcciones IP y direcciones de red para aceptar o denegar. Esta función de nftables nos permitirá realizar algo similar, el objetivo es poder añadir o quitar elementos fácilmente, sin tener que definir nuevas reglas constantemente.

nft add set inet firewall ips_baneadas { type ipv4_addr\;}
nft add element inet firewall ips_baneadas { 192.168.1.2 }
nft add element inet firewall ips_baneadas { 192.168.1.3, 192.168.4.66 }
nft add rule inet firewall bloqueo ip saddr @ips_baneadas counter drop

Los “type” pueden ser: “ipv4_addr, ipv6_addr, ether_addr, inet_proto, inet_service”

Source NAT: configuración del postrouting en nftables

La configuración del Source NAT en nftables es muy similar a como lo hacíamos con iptables. Lo primero que debemos hacer es crear una tabla con el nombre que queramos, y crear una cadena, a continuación, definiremos el hook y la prioridad

nft add table nat
nft add chain nat prerouting { type nat hook prerouting priority 0 \; }
nft add chain nat postrouting { type nat hook postrouting priority 100 \; }

Una vez que hemos creado la cadena, ahora definiremos la regla. Esta regla la podemos utilizar cuando la dirección IP pública, o la IP que queremos NATear sea la misma siempre:

nft add rule nat postrouting ip saddr 192.168.1.0/24 oif eth0 snat 1.2.3.4

O también masquerade para que no dependamos de que la dirección IP sea la misma:

nft add rule nat postrouting masquerade

Destination NAT: configuración del prerouting en nftables

La configuración del Destination NAT en nftables es muy similar a como lo hacíamos con iptables. Lo primero que debemos hacer es crear una tabla con el nombre que queramos, y crear una cadena, a continuación, definiremos el hook y la prioridad

nft add table nat
nft add chain nat prerouting { type nat hook prerouting priority 0 \; }
nft add chain nat postrouting { type nat hook postrouting priority 100 \; }

Una vez que hemos creado la cadena, ahora definiremos la regla. Esta regla sirve para hacer el reenvío de puertos TCP con destino 80 y 443, a la dirección IP privada definida:

nft add rule nat prerouting iif eth0 tcp dport { 80, 443 } dnat 192.168.1.120

En el caso de querer hacer redirección de puertos, para utilizar un Proxy o realizar un MitM, lo haremos de forma muy parecida en iptables:

nft add table nat
nft add chain nat prerouting { type nat hook prerouting priority 0 \; }
nft add chain nat postrouting { type nat hook postrouting priority 100 \; }

Una vez que hemos creado la cadena, ahora definiremos las reglas.

nft add rule nat prerouting redirect
nft add rule nat prerouting tcp dport 22 redirect to 2222

Otros ejemplos de nftables

Usamos “ct” para controlar las conexiones nuevas, establecidas y relacionadas.

ct state established,related accept

Conexiones no válidas:

ct state invalid drop

Controlar los diferentes tipos de ICMP

ip protocol icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem } accept

Controlar un límite de pings recibidos

ip protocol icmp icmp type echo-request limit rate over 10/second burst 4 packets drop

Limitar un número de intentos máximos de SSH

tcp dport ssh ct state new limit rate 15/minute accept

Si queremos “jump” o saltar a otra cadena, podemos hacerlo muy fácilmente y de manera más intuitiva:

table inet filter {
chain ssh_server {
tcp dport ssh accept
}
chain input {
type filter hook input priority 0;
ip saddr 10.10.2.2/24 jump ssh_server
drop
}
}

Tal y como habéis visto, nftables es bastante más fácil de utilizar que iptables, es más intuitivo. No obstante, para los que estamos acostumbrados a iptables, tendremos que trabajar y actualizarnos con la nueva sintaxis que incorpora nftables. Esperamos que este tutorial sobre las características y configuración básica de nftables os sirva de ayuda y practiquéis con el nuevo firewall Linux.