LinuxParty

Inicio desactivadoInicio desactivadoInicio desactivadoInicio desactivadoInicio desactivado
 

En uno de nuestros servidores Linux administrados, comenzamos a observar un comportamiento bastante extraño: el firewall funcionaba correctamente, pero, sin motivo aparente, todas sus reglas desaparecían.

Al ejecutar:

iptables -L -n

encontrábamos las cadenas vacías y las políticas predeterminadas en ACCEPT. Es decir, el servidor continuaba funcionando, pero había perdido todas las reglas de bloqueo que debían protegerlo.

Lo más desconcertante era que, después de restaurar el firewall, las reglas volvían a desaparecer pocos minutos después.

En este artículo explicamos la investigación que realizamos, las pistas que encontramos y cómo descubrimos que APF estaba ejecutando periódicamente un flush de todas las reglas de iptables.

Un script de vigilancia detectó la caída

El servidor contaba con un script propio que se ejecutaba periódicamente desde cron. Su función era comprobar el estado de diferentes servicios esenciales:

cat /root/bin/Comprueba.sh

Su contenido era similar al siguiente:

#!/bin/bash
#
# Comprueba que una serie de servicios
#

echo "Comprobando 1 de 10"
/root/bin/compruebasshd.sh

echo "Comprobando 2 de 10"
/root/bin/compruebafirewall.sh

echo "Comprobando 3 de 10"
/root/bin/compruebanamed.sh

echo "Comprobando 4 de 10"
/root/bin/compruebanamed-old.sh

echo "Comprobando 5 de 10"
/root/bin/compruebapostfix.sh

echo "Comprobando 6 de 10"
/root/bin/compruebadovecot.sh

echo "Comprobando 7 de 10"
/root/bin/compruebaccesosfallidos.sh

if [ ! -f /root/cargatrabajo.tmp ]; then
    echo "Comprobando 8 de 10"
    /root/bin/compruebahttpd.sh

    echo "Comprobando 9 de 10"
    /root/bin/compruebanginx.sh

    echo "Comprobando 10 de 10"
    /root/bin/compruebamysqld.sh
fi

if [ -f /root/cargatrabajo.tmp ]; then
    source /root/cargatrabajo.tmp

    quedan=$(echo "$quedan - 1" | bc)

    echo "Quedan: $quedan - $(date) -> $A" >> "$REGISTROSLOGS"
    echo "quedan=$quedan" > /root/cargatrabajo.tmp

    if [ "$quedan" -le 0 ]; then
        rm -f /root/cargatrabajo.tmp
        /root/bin/cargatrabajo.sh
    else
        exit 0
    fi
fi

Entre esas comprobaciones se encontraba:

/root/bin/compruebafirewall.sh

Este segundo script examinaba las reglas de iptables y buscaba alguna regla que utilizara el destino DROP:

CadenaFW=$(/sbin/iptables -L -n | grep DROP)

if [ "$CadenaFW" == "" ]; then
    /sbin/service iptables restart
    /sbin/service fail2ban restart

    /usr/bin/chmod a+x /root/addreglasxtras.sh
    /root/addreglasxtras.sh

    /root/bin/addreglasfromfwnuevos.sh > /root/sec.sh
    /usr/bin/chmod a+x /root/sec.sh
    /root/sec.sh

    echo "$(date) - SE CAYÓ EL FIREWALL" >> /root/logeaeldia.log

    echo "$(date) - LEVANTANDO EL SERVICIO DEL FIREWALL" |
        mail -s "$(hostname) FIREWALL CAÍDO" Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.
fi

Cuando el script no encontraba ninguna regla DROP, consideraba que el firewall estaba caído e intentaba recuperarlo.

Gracias a esta vigilancia recibíamos un correo cada vez que sucedía el problema. El script detectaba correctamente que las reglas habían desaparecido, pero todavía no sabíamos quién las estaba borrando.

¿Estaba realmente caído el servicio iptables?

Una de las primeras comprobaciones fue consultar el estado del servicio:

systemctl status iptables --no-pager -l

El resultado mostraba algo parecido a:

iptables.service - IPv4 firewall with iptables
Loaded: loaded
Active: active (exited)

La indicación active (exited) puede parecer un fallo, pero en iptables-services es completamente normal.

iptables no necesita mantener un proceso ejecutándose permanentemente. El servicio carga las reglas en el kernel y después termina. Las reglas continúan aplicándose aunque no exista un proceso llamado iptables.

Por este motivo, una comprobación como la siguiente no es fiable:

ps ax | grep -v grep | grep iptables

No encontrar un proceso llamado iptables no significa que el firewall esté detenido.

Una comprobación más adecuada sería:

systemctl is-active --quiet iptables

Pero incluso eso solo confirma el estado administrativo del servicio. Para asegurarnos de que existen reglas reales podemos utilizar:

iptables-save | grep -q -- '-A INPUT'

La advertencia sobre iptables-legacy

Durante la investigación también apareció este mensaje:

Warning: iptables-legacy tables present, use iptables-legacy to see them

Comprobamos que el comando iptables estaba enlazado con el frontend nftables:

readlink -f "$(command -v iptables)"

El resultado fue:

/usr/sbin/xtables-nft-multi

Sin embargo, el kernel también tenía cargadas tablas del backend antiguo:

cat /proc/net/ip_tables_names

Resultado:

mangle
filter

Esto indicaba una convivencia entre tablas nftables y tablas legacy.

La advertencia no significaba por sí sola que el firewall hubiera fallado. Simplemente informaba de que existían tablas legacy que el comando actual no podía mostrar.

No obstante, al consultar las reglas visibles encontramos únicamente:

iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT

En ese momento sí estaba claro que el conjunto de reglas consultado se encontraba vacío.

Las reglas guardadas seguían siendo válidas

El servidor conservaba una copia de las reglas en:

/etc/sysconfig/iptables

Comprobamos su sintaxis sin aplicarlas:

iptables-restore --test /etc/sysconfig/iptables
echo $?

El código devuelto fue:

0

Por tanto, el archivo era válido y contenía las cadenas y reglas esperadas, incluidas reglas propias, cadenas de Fail2Ban y numerosos bloqueos de direcciones IP.

Podíamos restaurarlas mediante:

iptables-restore < /etc/sysconfig/iptables

Después de restaurarlas, el firewall volvía a funcionar. Sin embargo, poco después desaparecían nuevamente.

Esto demostraba que el problema no estaba en el archivo guardado, sino en algún proceso que actuaba posteriormente sobre las tablas.

La investigación con journalctl

Para descubrir qué sucedía exactamente en los minutos posteriores a la restauración utilizamos el journal de systemd:

journalctl --since "-5 minutes" --no-pager |
grep -iE 'iptables|fail2ban|firewall|CROND|systemctl|service'

En los registros apareció una secuencia muy reveladora:

01:49:58 Stopping IPv4 firewall with iptables...
01:49:59 iptables: Flushing firewall rules: [ OK ]
01:49:59 Starting IPv4 firewall with iptables...
01:49:59 iptables: Applying firewall rules: [ OK ]
01:49:59 Started IPv4 firewall with iptables.

Hasta ahí, el comportamiento era el esperado: el servicio había restaurado correctamente las reglas.

Pero apenas dos segundos después apareció esta ejecución:

01:50:01 CROND root: /etc/apf/apf -f

Habíamos encontrado al responsable.

APF ejecutaba un flush cada cinco minutos

APF, o Advanced Policy Firewall, no es un firewall independiente de iptables. Es una herramienta que administra y modifica las mismas reglas de Netfilter.

Por ese motivo:

apf -l

mostraba reglas similares a:

iptables -L -n

La opción problemática era:

apf -f

La opción -f realiza un flush, es decir, vacía las reglas administradas por el firewall.

Buscamos dónde estaba programada esa ejecución:

grep -RniF '/etc/apf/apf -f' \
    /etc/crontab \
    /etc/cron.d \
    /etc/cron.hourly \
    /etc/cron.daily \
    /var/spool/cron 2>/dev/null

El resultado fue:

/etc/cron.d/apf_develmode:1:*/5 * * * * root /etc/apf/apf -f >> /dev/null 2>&1

El contenido de /etc/cron.d/apf_develmode era:

*/5 * * * * root /etc/apf/apf -f >> /dev/null 2>&1

Eso significaba que APF vaciaba deliberadamente las reglas de iptables cada cinco minutos.

El ciclo era, por tanto, el siguiente:

  1. iptables cargaba correctamente las reglas.
  2. Nuestro script comprobaba que el firewall estaba funcionando.
  3. APF ejecutaba apf -f.
  4. Todas las reglas desaparecían.
  5. Nuestro monitor detectaba que ya no existían reglas DROP.
  6. El script reiniciaba iptables y Fail2Ban.
  7. Las reglas volvían a cargarse.
  8. Cinco minutos después, APF volvía a vaciarlas.

No era una caída espontánea ni una intrusión. Dos sistemas de administración estaban compitiendo sobre las mismas tablas.

Por qué existía esa tarea programada

El nombre del archivo proporcionaba una pista:

apf_develmode

APF puede utilizar un modo de desarrollo pensado para evitar que una configuración incorrecta del firewall deje al administrador sin acceso al servidor.

Cuando se trabaja remotamente mediante SSH, una regla incorrecta podría bloquear el acceso. Para reducir ese riesgo, el modo de desarrollo programa un vaciado periódico de reglas.

Es una protección útil durante una configuración inicial, pero no debe permanecer activa permanentemente en un servidor de producción.

Comprobamos la configuración con:

grep -nE '^[[:space:]]*DEVEL_MODE' /etc/apf/conf.apf

Si aparece:

DEVEL_MODE="1"

APF continúa en modo desarrollo.

Para un servidor en producción, una vez revisadas cuidadosamente las reglas, debe quedar configurado como:

DEVEL_MODE="0"

Antes de hacer este cambio hay que asegurarse de que el acceso SSH esté permitido. De lo contrario, una configuración incorrecta podría dejar el servidor inaccesible.

Cómo desactivamos el vaciado automático

La primera medida fue comentar la tarea programada:

# */5 * * * * root /etc/apf/apf -f >> /dev/null 2>&1

El archivo quedó así:

cat /etc/cron.d/apf_develmode
# */5 * * * * root /etc/apf/apf -f >> /dev/null 2>&1

Con ello cron dejó de ejecutar el vaciado cada cinco minutos.

También es necesario revisar /etc/apf/conf.apf y desactivar permanentemente el modo de desarrollo:

DEVEL_MODE="0"

De lo contrario, una futura recarga, reinstalación o actualización de APF podría volver a generar la tarea programada.

Después restauramos las reglas:

iptables-restore < /etc/sysconfig/iptables

Las guardamos nuevamente:

service iptables save

Y habilitamos su carga durante el arranque:

systemctl enable iptables

Finalmente verificamos:

systemctl is-enabled iptables
systemctl is-active iptables
iptables -S

Esperamos más de cinco minutos y repetimos la consulta. Las reglas continuaban cargadas, confirmando que APF era quien las eliminaba.

Mejoras necesarias en nuestros scripts de vigilancia

La investigación también nos permitió detectar algunas comprobaciones antiguas que convenía modernizar.

No comprobar iptables mediante ps

Esta comprobación no es válida:

ps ax | grep -v grep | grep iptables

iptables-services puede encontrarse correctamente como active (exited) sin mantener ningún proceso residente.

Es preferible utilizar:

systemctl is-active --quiet iptables

No depender únicamente de la palabra DROP

Buscar una regla DROP puede servir como comprobación rápida, pero no garantiza que todo el firewall esté correctamente cargado:

iptables -L -n | grep DROP

Una verificación más sólida puede comprobar la existencia de reglas concretas o contar las reglas de la cadena INPUT:

iptables-save | grep -q -- '-A INPUT'

Por ejemplo:

if systemctl is-active --quiet iptables &&
   iptables-save | grep -q -- '-A INPUT'
then
    echo "Firewall cargado correctamente"
else
    echo "Firewall sin reglas; intentando restaurar"

    if iptables-restore --test /etc/sysconfig/iptables; then
        iptables-restore < /etc/sysconfig/iptables
        systemctl restart fail2ban
    else
        echo "ERROR: /etc/sysconfig/iptables no es válido"
    fi
fi

En un sistema con tablas nft y legacy mezcladas, también debe verificarse que la herramienta consultada corresponde al backend que realmente contiene las reglas.

Mejorar el archivo de bloqueo

El script utilizaba /root/fwfuncionando.tmp como semáforo para evitar ejecuciones simultáneas. Sin embargo, en la rama que recuperaba el firewall no siempre eliminaba el archivo temporal.

Puede resolverse mediante:

trap 'rm -f /root/fwfuncionando.tmp' EXIT

Una opción más robusta sería utilizar flock:

exec 9>/run/compruebafirewall.lock
flock -n 9 || exit 0

Así se evita que dos instancias modifiquen simultáneamente las tablas.

Demasiados gestores para un mismo firewall

En el servidor coexistían varias herramientas capaces de modificar Netfilter:

  • iptables-services.
  • APF.
  • Fail2Ban.
  • BFD.
  • DDOS Deflate.
  • Imunify360.
  • Scripts propios de bloqueo y monitorización.

La convivencia es posible, pero debe existir un responsable principal de la configuración.

En nuestro caso, la arquitectura más razonable es:

  • iptables-services para guardar y restaurar las reglas principales.
  • Fail2Ban para los bloqueos dinámicos.
  • Scripts propios para incorporar reglas adicionales y verificar el estado.
  • APF desactivado como gestor automático si ya no resulta necesario.
  • Revisión de BFD, DDOS Deflate e Imunify360 para asegurarnos de que no recargan o vacían las tablas completas.

Cuando varias herramientas intentan administrar el mismo firewall, una recarga de cualquiera de ellas puede eliminar reglas creadas por las demás.

¿Se instaló APF junto con Maldet?

Durante la investigación observamos que el directorio de APF y el paquete descargado de Linux Malware Detect presentaban fechas prácticamente idénticas.

Ambas herramientas proceden de R-fx Networks, lo que inicialmente hizo sospechar que APF podía haberse instalado junto con Maldet.

Sin embargo, la instalación oficial actual de Linux Malware Detect no incluye APF como componente obligatorio. La coincidencia de fechas puede indicar:

  • La ejecución de un instalador combinado.
  • La instalación consecutiva de varias herramientas de R-fx Networks.
  • Un script externo que instaló ambos productos.
  • Una reinstalación o actualización realizada durante la misma sesión.

Para comprobar el paquete concreto descargado utilizamos:

grep -RniE '(/etc/apf|apf_develmode|advanced policy firewall|rfxn.*apf)' \
    /root/tmp/linux-malware-detect 2>/dev/null

Por tanto, no debe atribuirse la instalación de APF a Maldet únicamente por la coincidencia de fechas sin revisar antes el instalador exacto utilizado.

Conclusión

El firewall no se caía por un fallo de iptables. APF estaba ejecutando conscientemente:

/etc/apf/apf -f

cada cinco minutos desde:

/etc/cron.d/apf_develmode

Nuestro sistema de vigilancia detectaba correctamente la desaparición de las reglas y las restauraba, pero APF volvía a vaciarlas en la siguiente ejecución programada.

La orden que permitió descubrirlo fue:

journalctl --since "-5 minutes" --no-pager |
grep -iE 'iptables|fail2ban|firewall|CROND|systemctl|service'

La investigación demuestra por qué, cuando un firewall pierde sus reglas de forma periódica, no basta con restaurarlas. Hay que revisar:

  • El journal de systemd.
  • Las tareas de cron.
  • Los gestores de firewall instalados.
  • Los scripts propios.
  • La convivencia entre iptables-nft e iptables-legacy.
  • Los modos de desarrollo que programan vaciados preventivos.

En nuestro caso, una sola línea de cron explicaba todo el comportamiento:

*/5 * * * * root /etc/apf/apf -f

Comentada esa línea y desactivado el modo de desarrollo de APF, las reglas dejaron de desaparecer.



Desinstalar APF: una buena práctica antes de cambiar de solución

Si has instalado APF para realizar pruebas y decides volver a utilizar el firewall nativo de tu distribución, conviene eliminarlo completamente para evitar posibles conflictos.

Comprobar si APF está en ejecución

Antes de eliminar nada, verifica si el servicio está activo:

systemctl status apf

También puedes comprobar si se inicia automáticamente con el sistema:

systemctl is-enabled apf

Si el servicio está activo, deténlo y desactívalo:

sudo systemctl stop apf
sudo systemctl disable apf

Eliminar los archivos instalados

APF no incorpora actualmente un script oficial de desinstalación, por lo que basta con eliminar los archivos que instaló:

sudo rm -rf /etc/apf

sudo rm -f /usr/local/sbin/apf
sudo rm -f /usr/local/sbin/fwmgr

sudo rm -f /etc/systemd/system/apf.service
sudo systemctl daemon-reload

sudo rm -f /etc/cron.d/apf

sudo rm -f /etc/bash_completion.d/apf

sudo rm -f /etc/logrotate.d/apf

sudo rm -f /usr/share/man/man8/apf.8.gz
sudo mandb

Si descargaste el código fuente únicamente para instalarlo, también puedes eliminar el directorio donde lo clonaste:

rm -rf /root/tmp/advanced-policy-firewall

Comprueba el estado de firewalld

Existe un detalle importante que muchos administradores pasan por alto.

Durante la instalación, APF detecta si firewalld o ufw están activos y, en caso afirmativo, puede detenerlos y deshabilitarlos para evitar conflictos, ya que APF gestiona directamente las reglas de iptables.

Por ello, una vez eliminado APF es recomendable comprobar el estado de firewalld:

systemctl status firewalld
systemctl is-enabled firewalld

Si deseas volver a utilizar el firewall estándar de RHEL, AlmaLinux, Rocky Linux o Fedora, simplemente actívalo de nuevo:

sudo systemctl enable --now firewalld

Una recomendación

Antes de instalar cualquier herramienta de seguridad conviene evaluar si realmente aporta alguna ventaja respecto a las soluciones incluidas en la distribución.

APF fue una herramienta excelente durante muchos años y marcó una época en la administración de servidores Linux. Sin embargo, en sistemas actuales suele ser más recomendable utilizar firewalld, nftables o el firewall integrado del panel de administración, manteniendo APF únicamente por motivos de compatibilidad con entornos heredados.



Eliminando el aviso «iptables-legacy tables present»

Tras desinstalar APF es posible que, al ejecutar cualquier comando de iptables, aparezca un mensaje similar al siguiente:

# Warning: iptables-legacy tables present, use iptables-legacy to see them

Este aviso suele generar bastante confusión, ya que puede aparecer incluso cuando APF ya no está instalado y el sistema utiliza el backend moderno basado en nf_tables.

En realidad, el problema no reside en iptables, sino en que todavía permanecen cargadas en el kernel algunas tablas heredadas (legacy) creadas durante la ejecución de APF u otras herramientas antiguas de administración del cortafuegos.

Podemos comprobar fácilmente si existen tablas heredadas:

cat /proc/net/ip_tables_names

Si el resultado muestra algo parecido a:

mangle
filter

significa que todavía existen tablas iptables-legacy activas en memoria.

En nuestro caso, el responsable era el módulo del kernel iptable_mangle, que permanecía cargado aunque APF ya hubiera sido desinstalado.

Podemos comprobar qué módulos siguen activos mediante:

lsmod | grep iptable

La solución consiste en descargar dichos módulos del kernel:

sudo modprobe -r iptable_mangle
sudo modprobe -r iptable_filter

Una vez descargados, comprobamos de nuevo el estado:

cat /proc/net/ip_tables_names

Si el comando ya no devuelve ninguna salida, significa que las tablas heredadas han desaparecido correctamente.

A partir de ese momento, el aviso:

Warning: iptables-legacy tables present

dejará de aparecer al utilizar iptables.

Importante

Si algún módulo no puede descargarse porque está siendo utilizado (Module ... is in use), conviene comprobar previamente que ningún servicio (APF, CSF, firewalld u otro firewall) continúe utilizándolo antes de forzar su eliminación. En algunos casos, un simple reinicio del servidor también elimina definitivamente las tablas heredadas si ya no existe ningún servicio que vuelva a cargarlas.

Este comportamiento no es un fallo de iptables, sino una consecuencia de mantener cargados en memoria módulos del antiguo subsistema xtables, aun cuando el sistema ya trabaja con el backend moderno basado en nf_tables.

No estás registrado para postear comentarios



Redes:



   

 

Suscribete / Newsletter

Suscribete a nuestras Newsletter y periódicamente recibirás un resumen de las noticias publicadas.

Donar a LinuxParty

 

Tutorial de Linux

Top 15 artículos por Fecha

Viendo artículos de: Junio de 2026

Filtro por Categorías