Muchos sysadmins estamos acostumbrados a utilizar Frontends del firewall iptables para facilitarnos el trabajo, como por ejemplo APF Firewall. Yo soy uno de ellos. Independientemente de esto, conviene saber como funciona iptables de forma interna para evitar la dependencia de este tipo de aplicaciones de terceros para configurar de forma correcta el firewall del kernel Linux. Vamos a ver algunos puntos que nos ayudarán a comprender su funcionamiento.
Listar reglas, Chain y políticas de Iptables
Con estos comandos podemos ver de un vistazo la configuración establecida en el firewall.
Ver el listado de reglas activas en el firewall:
# iptables -L
Borrar todas las reglas establecidas en el firewall:
# iptables -F
Pone a 0 los contadores de bytes y paquetes:
# iptables -Z
Iptables tiene 3 Chain (cadenas) sobre las cuales construir las reglas, establecer políticas comunes, etc: INPUT, FORWARD y OUTPUT. La política por defecto para ellas es de aceptar todo:
# iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination
También podemos listar únicamente las reglas y política de una Chain concreta:
# iptables -L INPUT Chain INPUT (policy ACCEPT) target prot opt source destination
Si no fuera suficiente estas tres Chain podemos crear nuevas o eliminar podemos hacerlo, así como renombrar las ya existentes:
Crear una nueva Chain llamada TEST:
# iptables -N TEST
Eliminarla:
# iptables -X TEST
Renombrarla a TEST2:
# iptables -E TEST TEST2
Establecer políticas por defecto
Para poder empezar a configurar Iptables debemos partir de una base, una política por defecto que aceptará o denegará el tráfico para cada una de las Chain vistas anteriormente (INPUT OUTPUT o FORWARD). Si quisierais blindar el sistema podríais partir de una base ‘paranoica‘ denegando todo:
# iptables -P INPUT DENY # iptables -P OUTPUT DENY # iptables -P FORWARD DENY
En el momento que lo hicierais perderíais toda conectividad en la máquina, así que nosotros vamos a comenzar aceptando todo y aplicando pequeñas restricciones en nuestra máquina, una vez configurado todo es cuando podríamos aplicar la configuración restrictiva de arriba:
# iptables -P INPUT ACCEPT # iptables -P OUTPUT ACCEPT # iptables -P FORWARD ACCEPT
Veréis que estamos añadiendo las reglas directamente desde la línea de comandos, lo óptimo es añadirlas dentro de un script para así ejecutarlo todo de forma automática cuando arrancamos el equipo, lo veremos después.
Filtrado de puertos, IPs, rangos…
Una vez establecida la política por defecto, podemos comenzar a definir nuestras reglas específicas para cada cadena (Chain). La estructura del comando usado para filtrado de puertos, ips, etc es la siguiente:
Filtrado/apertura de un puerto/rango de puertos
# iptables -A <INPUT|OUTPUT|FORWARDING> -p <tcp|udp> --dport <PUERTO_DESTINO> -j <ACCEPT|DROP>
Así por ejemplo si quisieramos cerrar el puerto de entrada tcp 21 (FTP) para toda la máquina:
# iptables -A INPUT -p tcp --dport 21 -j DROP
Permitir el tráfico de entrada por el puerto 80, necesario por ejemplo si el equipo es un servidor web:
# iptables -A INPUT -p tcp --dport 80 -j ACCEPT
Para bloquear un rango de puertos, simplemente especificamos el primer y último puerto del rango, en este ejemplo bloqueamos la salida tcp de los puertos 2000 al 3000:
# iptables -A OUTPUT -p tcp --dport 2000:3000 -j DROP
Permitir/denegar puertos a determinadas IPs, interfaces de red o CIDR
# iptables -A <INPUT|OUTPUT|FORWARDING> -s <IP|RANGO> -p <tcp|udp> --dport <PUERTO_DESTINO> -j <ACCEPT|DROP>
Es probable que necesitemos configurar políticas de aceptación o denegación de puertos a determinadas IPs, o incluso el acceso/denegación total a las mismas. La IP la especificaremos con el parámetro -s. Vamos a ver unos ejemplos:
Aceptar todo el tráfico de entrada de una IP:
# iptables -A INPUT -s 192.168.1.128 -j ACCEPT
Denegar todo el tráfico de entrada a una IP:
# iptables -A INPUT -s 192.168.1.128 -j DROP
Aceptar a una IP el acceso a un determinado puerto:
# iptables -A INPUT -s 192.168.1.128 -p tcp --dport 25 -j ACCEPT
Para el tema de rangos, podemos usar la notación CIDR. Vamos a aceptar todo el tráfico en la red local:
# iptables -A INPUT -s 192.168.0.0/24 -j ACCEPT
También podemos especificar reglas restringiendo según interfaces de red en lugar de IPs o rangos. Esto lo hacemos mediante el parámetro -i:
# iptables -A INPUT -i eth0 -j ACCEPT
Nuestro primer script de Iptables
Antes de hacer el script conviene saber qué puertos tenemos abiertos en la máquina para configurarlos previamente y evitar problemas. Podemos usar nmap o netstat para averiguarlo. Un ejemplo de un típico servidor con servicios web, MySQL, correo, etc podría ser el siguiente:
# nmap -sTU localhost Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2011-08-27 21:14 CEST Interesting ports on localhost (127.0.0.1): Not shown: 3152 closed ports PORT STATE SERVICE 1/tcp open tcpmux 21/tcp open ftp 25/tcp open smtp 80/tcp open http 110/tcp open pop3 143/tcp open imap 443/tcp open https 465/tcp open smtps 783/tcp open spamassassin 993/tcp open imaps 995/tcp open pop3s 3306/tcp open mysql 161/udp open|filtered snmp
La salida de nmap nos ofrece una guía clara sobre los puertos a abrir. A partir de aquí es cuestión de construir nuestro script con las reglas correspondientes, estableciendo primero las políticas generales y luego definiendo el filtrado/apertura concreta de puertos, si queremos restringir puertos a determinadas IPs, bloquear el acceso a rangos CIDR, etc.
#!/bin/sh # Primero limpiamos cualquier regla haciendo un flush # tambien reseteamos contadores (-Z) y las Chain personalizadas # que se hayan creado (-X) iptables -F iptables -X iptables -Z # Politicas por defecto (ACEPTAR TODO) iptables -P INPUT ACCEPT iptables -P OUTPUT ACCEPT iptables -P FORWARD ACCEPT # Cerramos ssh excepto para nuestra red privada iptables -A INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT iptables -A INPUT -p tcp --dport 22 -j DROP # Tenemos un servidor MySQL pero únicamente para servir en local iptables -A INPUT -p tcp --dport 3306 -i lo -j ACCEPT iptables -A INPUT -p tcp --dport 3306 -j DROP # Aceptamos todas las conexiones FTP, HTTP y HTTPS iptables -A INPUT -p tcp --dport 21 -j ACCEPT iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j ACCEPT # Servicios de correo iptables -A INPUT -p tcp --dport 25 -j ACCEPT iptables -A INPUT -p tcp --dport 143 -j ACCEPT iptables -A INPUT -p tcp --dport 110 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j ACCEPT iptables -A INPUT -p tcp --dport 465 -j ACCEPT iptables -A INPUT -p tcp --dport 993 -j ACCEPT iptables -A INPUT -p tcp --dport 995 -j ACCEPT # SNMP lo vamos a permitir para nuestra red local iptables -A INPUT -p udp --dport 161 -s 192.168.1.0/24 -j ACCEPT iptables -A INPUT -p udp --dport 161 -j DROP # Una vez que hayamos abierto todo lo necesario, podemos cerrar # el resto o un rango especifico de puertos conocidos... iptables -A INPUT -p tcp --dport 1:1024 -j DROP iptables -A INPUT -p udp --dport 1:1024 -j DROP
Este es un ejemplo sencillo (¡ojo, no verificado!) que muestra las posibilidades más básicas de iptables, hay que tener en cuenta que no hemos tratado más que TCP y UDP sobre rasgos generales, no tratamos ICMP ni configuraciones detalladas. Para ello, os emplazo y recomiendo la guía que encontraréis el TLDP (The Linux Documentation Project) o a futuros artículos que complemetarán a este y enlazaré conforme vayamos avanzando.
Muy bien explicado, simple y conciso se te agradece