Cuando la comparación de una regla encuentra un paquete que coincide con las condiciones que impone (tal como hemos visto hasta ahora), se recurre al objetivo/salto dónde se le indica a la regla qué debe hacer con ese paquete. Hay dos objetivos básicos que trataremos primero: ACCEPT y DROP, pero antes de empezar veamos brevemente cómo se efectúa un salto.
La orden de salto se ejecuta de la misma manera que la orden de objetivo, excepto en que el salto necesita que exista una cadena dentro de la misma tabla a la que pueda dirigirse. Para crear una cadena, tal como ya se ha explicado, se utiliza el comando -N. Por ejemplo, supongamos que queremos crear una cadena en la tabla "filter" llamada tcp_packets, por lo que escribiremos:
iptables -N tcp_packets
A partir de entonces podremos referirnos a esa cadena para efectuar un salto siempre que lo necesitemos:
iptables -A INPUT -p tcp -j tcp_packets
De esta forma todos los paquetes TCP saltarán desde la cadena INPUT hasta la cadena tcp_packets y serán filtrados por élla. Si algún paquete llega al final de la cadena y no ha habido una concordancia (el paquete no presenta coincidencias con las reglas de la cadena), volverá a la cadena original (en nuestro caso la cadena INPUT) justo después de la regla que originó el salto y seguirá pasando por el resto de reglas de esta cadena. Por el contrario, si alguna de las reglas de la cadena "tcp_packets" acepta (ACCEPT) los paquetes, éstos efectuarán el salto/objetivo de la regla y seguirán su curso por el resto de cadenas, sin pasar nunca por el resto de reglas de la cadena de origen (INPUT). Para mayor información de cómo los paquetes atraviesan las tablas y cadenas, léete el capítulo Atravesando tablas y cadenas.
Por otra parte, los objetivos especifican la acción a ejecutar con el paquete en cuestión. Así, se podrá aceptar (ACCEPT) o desechar (DROP) el paquete dependiendo de lo que queramos hacer. Existen además otra serie de acciones que podemos querer hacer con el paquete, y las describiremos más adelante. Debes tener en cuenta que saltar a un objetivo puede dar diferentes resultados, dependiendo del que se trate. Algunos objetivos harán que el paquete deje de atravesar una cadena específica y todas las superiores a élla, como se ha descrito antes (buenos ejemplos de éllo son DROP y ACCEPT): las reglas que son paradas no pasarán ninguna regla más, ni de esa misma cadena, ni de ninguna cadena "superior" a élla (superiores serán aquellas que han producido saltos hacia la cadena actual: la cadena A produce un salto a la cadena B y ésta última a la cadena C, donde el paquete se para en alguna regla y por tanto deja de atravesar la cadena C y sus superiores, la A y la B). Otros objetivos pueden efectuar alguna acción sobre el paquete, después del cual éste continuará pasando por el resto de reglas. Por ejemplo tenemos los objetivos LOG, ULOG y TOS: con éllos podemos registrar los paquetes, modificarlos y después pasárselos a otras reglas en el mismo conjunto de cadenas. Podemos querer hacer ésto para, por ejemplo, poder modificar tanto el valor del TTL como el del TOS de un paquete/flujo específico. Algunos objetivos aceptan opciones adicionales (qué valor TOS utilizar, ...), mientras otros no necesitan opciones obligatoriamente (aunque se puedan incluir si se desea, como ocurre con los prefijos de los registros, los puertos que se enmascararán, ...). Intentaremos incluir todos estos puntos tal como describamos los objetivos, así que empecemos a ver qué tipo de objetivos hay.
Este objetivo no necesita ninguna opción adicional. En cuanto la especificación de la comparación es satisfecha por un paquete y se indica ACCEPT (aceptar) como objetivo, la regla se acepta y el paquete no continúa atravesando ni la cadena actual, ni cualquier otra de la misma tabla. Advierte sin embargo que un paquete que haya sido aceptado por una cadena todavía podría atravesar las cadenas de otras tablas y podría ser desechado en éllas. Para emplear este objetivo no hay más que indicar -j ACCEPT.
El objetivo DNAT se emplea para efectuar traducciones de direcciones de red de destino (Destination Network Address Translation), que significa que se emplea para reescribir la dirección IP de destino de un paquete. Con este objetivo en la regla, en cuanto un paquete coincide con la comparación, él y todos los paquetes pertenecientes a ese mismo flujo de datos verán modificada su dirección de destino y serán redirigidos a la red/host/dispositivo adecuado. Este objetivo puede ser extremadamente útil cuando, por ej., tienes un host ejecutando el servidor web dentro de una red local (LAN), pero sin una IP real que ofrecerle y que sea válida en Internet. Entonces puedes indicarle al cortafuegos que cuando lleguen paquetes dirigidos a su propio puerto HTTP los reenvíe hacia el servidor web real dentro de la red local. También se pueden especificar todo un rango de direcciones IP de destino y el mecanismo DNAT escogerá aleatoriamente la dirección IP de destino para cada flujo de datos. Mediante este sistema seremos capaces de abordar una especie de balance de carga.
Observa que el objetivo DNAT sólo está disponible en las cadenas PREROUTING y OUTPUT de la tabla nat, así como aquellas cadenas a las que las dos anteriores hayan dirigido un salto (es decir, cualquier cadena a la que se haya saltado desde una de las dos mencionadas). Insistimos en que las cadenas que contengan objetivos DNAT no pueden usarse desde otras cadenas, como podría ser el caso de la cadena POSTROUTING.
Table 6-16. Objetivo DNAT
Opción | --to-destination |
Ejemplo | iptables -t nat -A PREROUTING -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10 |
Descripción | La opción --to-destination le indica al mecanismo DNAT qué IP de Destino establecer en la cabecera IP y dónde enviar los paquetes que concuerden con el filtro. El ejemplo anterior enviará todos los paquetes destinados a la dirección IP 15.45.23.67 a un rango de direcciones LAN, en este caso el rango 192.168.1.1 a 192.168.1.10. Ten en cuenta que, tal como se ha dicho, un flujo concreto siempre usará el mismo host, mientras que a cada flujo se le asignará aleatoriamente una dirección IP a la que siempre serán destinados todos los paquetes de ese flujo. También se podría haber especificado una sola dirección IP, en cuyo caso siempre estaríamos conectados al mismo host. También podemos añadir un puerto o rango de puertos a los que será redirigido el tráfico. Para ello sólo tenemos que añadir el puerto o rango de puertos después de ":", como en --to-destination 192.168.1.1:80 para un puerto único, o como en --to-destination 192.168.1.1:80-100 para un rango de puertos. Como puedes ver, la sintaxis es la misma para los objetivos DNAT y SNAT, aunque es evidente que los resultados de uno y otro son totalmente diferentes. Por otra parte, las especificaciones de puertos sólo son válidas en aquellas reglas dónde se especifiquen los protocolos TCP o UDP en la opción --protocol. |
Puesto que el objetivo DNAT exige bastante trabajo para funcionar correctamente, he decidido ampliar la explicación sobre cómo usarlo. Para empezar estudiaremos un pequeño ejemplo acerca de cómo deberían hacerse las cosas normalmente: queremos publicar nuestro sitio web aprovechando nuestra conexión a Internet, aunque sólo tenemos una dirección IP y el servidor HTTP se encuentra en nuestra red interna. El cortafuegos tiene la dirección IP externa $INET_IP, nuestro servidor HTTP tiene la dirección IP interna $HTTP_IP y por último el cortafuegos tiene la dirección IP interna $LAN_IP. Lo primero que hay que hacer es añadir la siguiente regla a la cadena PREROUTING de la tabla nat:
iptables -t nat -A PREROUTING --dst $INET_IP -p tcp --dport 80 -j DNAT --to-destination $HTTP_IP
Desde ahora todos los paquetes que provengan de Internet y se dirijan al puerto 80 de nuestro cortafuegos, serán redirigidos a nuestro servidor HTTP interno. Si lo compruebas desde Internet, todo debería funcionar perfectamente. Pero, ¿qué ocurre cuando intentas conectar desde un host de la misma red local a la que pertenece el servidor HTTP?. Sencillo, simplemente no podrás. En realidad éste es un problema de enrutado: comenzaremos estudiando lo que ocurre en el caso normal. Para mantener la estructura del ejemplo, consideremos que la máquina externa tiene una dirección IP $EXT_BOX.
El paquete deja el host (con IP $EXT_BOX) que quiere conectar con la página web para dirigirse a $INET_IP.
El paquete llega al cortafuegos.
El cortafuegos efectúa la traducción DNAT en el paquete y lo envía a través del resto de cadenas.
El paquete deja el cortafuegos y viaja hacia $HTTP_IP.
El paquete llega al servidor HTTP y la máquina HTTP responde a través del cortafuegos (siempre que la base de datos de enrutado tenga definido el cortafuegos como el puente entre la red local y $EXT_BOX). En general éste será el puente por defecto del servidor HTTP.
El cortafuegos deshace la traducción que había hecho con DNAT sobre el paquete, de forma que parece que es el cortafuegos el que responde.
El paquete de respuesta viaja de vuelta al cliente $EXT_BOX.
Ahora consideremos qué ocurre si el paquete se origina en un cliente de la misma red a la que pertenece el servidor HTTP. El cliente tiene la dirección IP $LAN_BOX, mientras el resto de máquinas mantienen los mismos valores (nombres).
El paquete deja $LAN_BOX para dirigirse a $INET_IP.
El paquete llega al cortafuegos.
El paquete sufre la traducción DNAT y todas las acciones necesarias se toman en consecuencia, si bien al paquete no se le efectúa ninguna traducción SNAT y mantiene la misma dirección IP de origen.
El paquete sale del cortafuegos y alcanza el servidor HTTP.
El servidor HTTP intenta responder al paquete y observa en las bases de datos de enrutado que el paquete viene de una máquina local de la misma red, por lo que intenta enviar el paquete directamente a la dirección IP de origen (que a partir de ese momento se convierte en la dirección IP de destino).
El paquete llega al cliente, que no sabe qué hacer puesto que el paquete devuelto no proviene del host al que envió la petición original. Por éllo el cliente desecha el paquete y continúa esperando la respuesta "auténtica".
La solución más simple para este problema es efectuar la traducción SNAT a todos los paquetes que entren al cortafuegos y a los que sabemos que también se les va a aplicar la traducción DNAT. Por ej., consideremos la siguiente regla: vamos a efectuar una traducción SNAT a los paquetes que entren al cortafuegos y estén destinados a $HTTP_IP en el puerto 80, de forma que parecerá que provengan de $LAN_IP. Ésto forzará al servidor HTTP a devolver los paquetes a través del cortafuegos, que invertirá la traducción DNAT y los reenviará al cliente. La regla será algo así:
iptables -t nat -A POSTROUTING -p tcp --dst $HTTP_IP --dport 80 -j SNAT \ --to-source $LAN_IP
Recuerda que la cadena POSTROUTING se procesa en último lugar, después del resto de cadenas, por lo que el paquete será "retraducido" cuando llegue a esa cadena específica. Por éllo comparamos los paquetes en función de su dirección interna.
Esta última regla afectará seriamente el registro de actividades, por lo que es altamente recomendable no emplear este método, si bien el ejemplo todavía es válido para aquellos que no pueden permitirse crear una "zona desmilitarizada" (DMZ) específica o algo parecido. Lo que ocurrirá es que el paquete llegará desde Internet, sus direcciones IP serán traducidas por SNAT y por DNAT, llegando por fin al servidor HTTP (por ejemplo). El servidor sólo verá una petición que viene del cortafuegos y, por tanto, registrará todas las peticiones de Internet como si vinieran del cortafuegos. También pueden haber consecuencias más serias. Piensa en un servidor SMTP de la red local: éste admite peticiones desde la red interna y tienes configurado el cortafuegos de forma que redirija el tráfico SMTP hacia el servidor. Lo que has creado en la práctica es un servidor SMTP "universal" [en inglés se llama "open relay SMTP server", es decir, un servidor de correo que acepta servir mensajes que no ha escrito ningún usuario local, ni van destinados a ningún usuario local], ¡con un registro de eventos horroroso! Así pues, será mejor que resuelvas estos problemas configurando un servidor DNS distinto y separado para tu red local, o creando una "zona desmilitarizada" (DeMilitarized Zone, DMZ) separada de la red interna. Esta última opción es la preferida, si es que tienes el dinero necesario para éllo. |
¿Crees que ya está todo solucionado? Bueno, por ahora sí, salvo que consideres un último aspecto dentro de todo este cuadro. ¿Qué pasaría si el cortafuegos intenta acceder al servidor HTTP? ¿Dónde irá a parar? Como puede suponerse, intentará acceder a su propio servidor HTTP y no al servidor que hay en $HTTP_IP. Para corregir este problema necesitamos añadir una regla DNAT más a la cadena OUTPUT. Siguiendo con el ejemplo anterior, la regla podría quedar así:
iptables -t nat -A OUTPUT --dst $INET_IP -p tcp --dport 80 -j DNAT \ --to-destination $HTTP_IP
Con esta última regla todo debería funcionar perfectamente: todas aquellas redes que no pertenezcan a la misma red del servidor HTTP funcionarán como la seda; todos los hosts de la misma red del servidor HTTP podrán conectar sin tropiezos; por último, el cortafuegos será capaz de efectuar conexiones por sí mismo. Todo funciona bien y no tiene por qué haber ningún tipo de problema.
Cabe destacar que estas reglas sólo controlan cómo se efectúan las traducciones DNAT y SNAT. Por éllo, quizá necesites otras reglas en la tabla "filter" (en la cadena FORWARD) para que los paquetes puedan atravesar el resto de cadenas. No olvides que todos los paquetes han pasado primero por la cadena PREROUTING y pueden haber cambiado sus direcciones de destino debido al DNAT de esta última cadena. |
El objetivo DROP (desechar) hace precisamente éso: desechar o "tirar" paquetes y no gastar ni ún segundo más de trabajo del procesador en éllos. Un paquete que llegue a una regla, coincida exactamente con el patrón de búsqueda de la comparación y sea desechado, será inmediatamente bloqueado. Ten en cuenta que esta acción puede llegar a tener en determinadas ocasiones un efecto no deseado, ya que puede dejar sockets (conexiones host-hardware) "muertos" en cualquier host. Una solución más acertada, cuando se puedan dar estas circunstancias, es usar el objetivo REJECT (rechazar), especialmente si quieres impedir que los escáners de puertos recojan demasiada información privada, como qué puertos tienes filtrados y otros detalles. Volviendo al objetivo, si se efectúa la acción DROP a un paquete dentro de una subcadena, este paquete ya no será procesado en ninguna de las cadenas principales de ninguna tabla: el paquete estará "muerto" de inmediato y, como ya se ha dicho antes, el objetivo no enviará ninguna información en ninguna dirección, ni siquiera a intermediarios como los routers (se puede decir que a partir de la acción de desechar el paquete es como si éste nunca hubiera existido).
El objetivo LOG se ha diseñado especialmente para registrar información detallada sobre los paquetes. Ésto podría considerarse ilegal, o simplemente como una forma de buscar defectos y fallos. Este objetivo ofrece información específica sobre los paquetes, como la mayoría de las cabeceras IP y otros datos considerados interesantes. Ésto se consigue a través del servicio de registro del núcleo, normalmente syslogd, y puede ser leída directamente con los registros de dmesg, o bien mediante otros programas. Es un objetivo excelente para depurar y afinar tus conjuntos de reglas, puesto que puedes ver qué paquetes van dónde y qué reglas se aplican en qué paquetes. También puede ser una gran idea usar el objetivo LOG en lugar del objetivo DROP mientras estás testeando una regla de la que no estás seguro al 100% en un cortafuegos en servicio que esté usando más gente, pues un error en el conjunto de reglas puede causar problemas severos de conectividad a todos los usuarios. Y si estás generando un registro realmente extenso, puede que encuentres interesante el objetivo ULOG, ya que puede escribir los registros directamente en bases de datos como las de MySQL.
Si obtienes registros de eventos directamente en pantalla y no es éso lo que quieres, no busques el problema en iptables o en Netfilter, sinó más bien en la configuración de tu syslogd (lo más probable es que el problema esté en el fichero /etc/syslog.conf). Para información sobre este tipo de problema, repásate la ayuda escribiendo en la línea de comando: man syslog.conf. |
El objetivo LOG hoy por hoy tiene 5 opciones que pueden ser interesantes si necesitas información específica, o si quieres establecer diferentes opciones con valores específicos. Las explicamos a continuación.
Table 6-17. Opciones del objetivo LOG
Opción | --log-level |
Ejemplo | iptables -A FORWARD -p tcp -j LOG --log-level debug |
Descripción | Esta es la opción con la que le indicas a iptables y a syslog qué nivel de registro utilizar. Para ver una lista completa de niveles de registro, léete el manual de syslog.conf. Normalmente se presentan los siguientes niveles de registro (o prioridades, como normalmente se les suele llamar): debug, info, notice, warning, warn, err, error, crit, alert, emerg y panic. El nivel error es el mismo que err, warn es lo mismo que warning y panic es lo mismo que emerg. Sin embargo la primera opción de cada pareja se considera obsoleta y está condenada a desaparecer, por lo que no uses error, warn ni panic. La prioridad define la severidad del mensaje registrado. Todos los mensajes se registran a través del servicio ofrecido por el núcleo. O sea que escribiendo kern.=info /var/log/iptables en tu fichero syslog.conf y dejando a continuación que todos tus mensajes de LOG de iptables usen el nivel de información de registro (info), causará que todos los mensajes aparezcan en el fichero /var/log/iptables. Recuerda que también pueden haber otros mensajes de otras partes del núcleo que utilicen la prioridad de información. Si quieres conocer más detalles acerca del registro, te recomiendo que leas los manuales de syslog y syslog.conf, así como otros COMOs (HOWTOs) y ayudas publicadas en Internet. |
Opción | --log-prefix |
Ejemplo | iptables -A INPUT -p tcp -j LOG --log-prefix "INPUT packets" |
Descripción | Esta opción le dice a iptables que añada un prefijo específico a todos los mensajes del registro, lo cual es útil al emplear aplicaciones como grep para efectuar un seguimiento de problemas específicos y de registros generados por diferentes reglas. El prefijo puede tener hasta 29 caracteres, incluyendo espacios en blanco y otros caracteres especiales. |
Opción | --log-tcp-sequence |
Ejemplo | iptables -A INPUT -p tcp -j LOG --log-tcp-sequence |
Descripción | Esta opción añadirá los números de la Secuencia TCP (TCP Sequence) a cada mensaje registrado. El número de la Secuencia TCP es un número especial que identifica a cada paquete e indica dónde encaja dentro de una secuencia TCP, además de cómo debe ser reensamblado un flujo. Ten en cuenta que esta opción constituye un riesgo de seguridad si los registros pueden ser leídos por usuarios no autorizados o hasta por el resto del mundo. De la misma forma es un riesgo el acceso no autorizado a cualquier registro que contenga datos generados por iptables. |
Opción | --log-tcp-options |
Ejemplo | iptables -A FORWARD -p tcp -j LOG --log-tcp-options |
Descripción | Esta opción registra las diferentes opciones presentes en las cabeceras de los paquetes TCP y puede ser útil cuando se intentan depurar los fallos o lo que pudiera llegar a ir mal. La opción no tiene ninguna variable ni nada parecido, como le ocurre a la mayoría de opciones de LOG. |
Opción | --log-ip-options |
Ejemplo | iptables -A FORWARD -p tcp -j LOG --log-ip-options |
Descripción | Con la opción --log-ip-options registraremos la mayoría de opciones presentes en las cabeceras de los paquetes IP. Trabaja exactamente igual que la opción --log-tcp-options, salvo porque trabaja sobre las opciones IP. Ésto puede ser útil al tratar de depurar o perseguir determinados delincuentes, además de para corregir errores (de la misma forma que la anterior opción). |
El objetivo MARK se usa para establecer marcas (marks) de Netfilter asociadas a paquetes específicos. Este objetivo sólo es válido en la tabla mangle y no funcionará fuera de élla. Los valores de las marcas pueden usarse conjuntamente con las capacidades de enrutado avanzado de Linux, de forma que se envíen diferentes paquetes por diferentes rutas y que se les pueda indicar que usen diferentes disciplinas para hacer cola (qdisc), ... Para mayor información acerca del enrutado avanzado, pásate por Linux Advanced Routing and Traffic Control HOW-TO. Ten en cuenta que el valor de la marca no se establece en el paquete mismo, sinó que es un valor asociado al paquete dentro del núcleo. Dicho de otro modo: no puedes esperar que estableciendo una "MARKa" en un paquete, ese valor permanezca en otro host. Si es éso lo que buscas, mejor mira en el objetivo TOS, que modificará el valor TOS de la cabecera IP.
Table 6-18. Opciones del objetivo MARK
Opción | --set-mark |
Ejemplo | iptables -t mangle -A PREROUTING -p tcp --dport 22 -j MARK --set-mark 2 |
Descripción | La opción --set-mark se necesita para establecer una marca, que tomará un valor entero. Por ejemplo, podemos establecer una marca con un valor "2" en un flujo específico de paquetes, o en todos los paquetes de un host específico, y efectuar un enrutado avanzado sobre ese flujo/host para incrementar o disminuir el ancho de banda de la red, ... |
El objetivo MASQUERADE se usa básicamente de la misma forma que el objetivo SNAT, pero sin requerir ninguna opción --to-source. La razón es que el objetivo MASQUERADE se creó para trabajar, por ej., con conexiones telefónicas estándar (dial-up), o con conexiones DHCP, que obtienen direcciones IP dinámicas al conectar a la red en cuestión. Ésto quiere decir que sólo debes usar el objetivo MASQUERADE con conexiones IP asignadas dinámicamente, en las que antes de conectar con el ISP no sabemos la dirección que tendremos. Si tienes una conexión IP estática, debes emplear el objetivo SNAT en su lugar.
Enmascarar una conexión significa que estableces la dirección IP utilizada por una tarjeta de red específica, en lugar de utilizar la opción --to-source, por lo que la dirección IP se obtiene automáticamente de la información de la tarjeta específica. El objetivo MASQUERADE también tiene la particularidad de que las conexiones se olvidan, se pierden, cuando una interfaz se viene abajo (o como se suele decir, "se cuelga"), lo cual es extremadamente bueno si "matamos" una interfaz específica. En este caso, si hubiéramos utilizado el objetivo SNAT, podríamos haber llegado a tener un montón de datos viejos de seguimiento de conexión, que podrían haber estado "flotando" por la memoria durante días, devorando casi toda la memoria de seguimiento de conexiones. Así pues el enmascaramiento es, en general, la opción adecuada al trabajar con líneas telefónicas estándar, dónde probablemente se nos asignará una IP diferente cada vez que conectemos. En estos casos al desconectar la conexión se pierde totalmente, puesto que se nos asigna una IP diferente al reconectar, por lo que resulta bastante tonto mantener las entradas existentes del seguimiento de conexiones.
A pesar de todo, es posible usar el objetivo MASQUERADE en lugar del SNAT aunque tengas una IP estática, si bien no es conveniente puesto que genera un gasto extra de recursos y pueden haber futuras inconsistencias que desbaratarán tus scripts y los harán "inútiles".
Recuerda que el objetivo MASQUERADE sólo es válido en la cadena POSTROUTING de la tabla nat, igual que el objetivo SNAT. Además, el objetivo MASQUERADE acepta una opción, aunque ésta sea opcional.
Table 6-19. Objetivo MASQUERADE
Opción | --to-ports |
Ejemplo | iptables -t nat -A POSTROUTING -p TCP -j MASQUERADE --to-ports 1024-31000 |
Descripción | La opción --to-ports se utiliza para establecer el puerto o puertos origen de los paquetes salientes. Puedes especificar un solo puerto, como en --to-ports 1025, o puedes especificar un rango de puertos, como en --to-ports 1024-3000 (con los puertos inicial y final del rango separados por un guión). Esta forma de indicarlo difiere de la selección por defecto de SNAT, tal como se describe en Objetivo SNAT. La opción --to-ports sólo es válida si en la regla se especifican los protocolos TCP o UDP mediante la comparación --protocol. |
El objetivo MIRROR es únicamente experimental y de demostración, por lo que estás avisado para no utilizarlo: puede dar como resultado bucles infinitos (entre otras lindezas) que desemboquen en serias Denegaciones de Servicio (Denial of Service, DoS). Este objetivo se emplea para invertir los campos de origen y destino en la cabecera IP y después retransmitir el paquete. Esto puede crear efectos realmente divertidos y apuesto a que gracias a este objetivo más de un endemoniado cracker ha penetrado en su propio ordenador. El resultado de utilizar este objetivo es simple, por decirlo de alguna manera: digamos que establecemos un objetivo MIRROR para el puerto 80 del ordenador A y el host B (que proviene de yahoo.com) quiere acceder al servidor HTTP del host A; en estas condiciones el objetivo MIRROR devolverá al host de yahoo la página web de su propio servidor HTTP en Yahoo.com.
Debes tener en cuenta que el objetivo MIRROR sólo es válido cuando se utiliza en las cadenas INPUT, FORWARD y PREROUTING, así como en aquellas cadenas definidas por uno mismo y que sean llamadas desde alguna de las anteriores cadenas. Además, los paquetes salientes derivados de este objetivo no pasan por ninguna de las cadenas normales de las tablas filter, nat o mangle, lo que puede dar lugar a bucles infinitos y un rosario de problemas que pueden derivar en dolores de cabeza imprevistos. Por ejemplo, un host puede enviar un paquete camuflado (spoofed) con un TTL de 255 a otro host que utilice el objetivo MIRROR, de forma que parezca que el paquete viene de un tercer host que también usa el objetivo MIRROR; como consecuencia el paquete irá y volverá de un extremo al otro incesantemente, hasta que se completen el número de saltos (hops) definidos; si sólo hay un salto entre hosts, el paquete irá y vendrá 240-255 veces (no está mal para un cracker, pues enviando 1,5 kbytes de datos será capaz de consumir 380 kbytes de la conexión; siempre teniendo en cuenta que éste sería el mejor resultado para el cracker, script kiddie, novato, o como quiera llamársele).
El objetivo QUEUE se emplea para poner en cola los paquetes dirigidos a programas y aplicaciones del Espacio de Usuario. Se usa con programas o utilidades que son externos a iptables y puede utilizarse, por ej., en contabilidad de red, o con aplicaciones específicas y avanzadas que filtren o den servicios de caché (proxy) a los paquetes. No desarrollaremos este objetivo en profundidad, puesto que la programación de esas aplicaciones excede los objetivos de este tutorial: para empezar costaría mucho tiempo y además esa documentación no tendría nada que ver con la programación de Netfilter e iptables; todo ésto debería estar perfectamente descrito en "COMO Programar Netfilter" (Netfilter Hacking HOW-TO).
El objetivo REDIRECT sirve para redirigir paquetes y flujos hacia la máquina. Ésto quiere decir que podemos redirigir todos los paquetes destinados a los puertos HTTP hacia un caché HTTP como squid, o hacia nuestro host. Los paquetes generados localmente son "mapeados" a la dirección 127.0.0.1, o lo que es lo mismo, se reescribe la dirección de destino con la de nuestro host en los paquetes que son reenviados o acciones similares. El objetivo REDIRECT es extremadamente recomendable si queremos un servicio de caché transparente, donde los hosts de la red local ni siquiera advierten que existe un caché (proxy).
Como viene siendo habitual, este objetivo sólo funciona en determinadas cadenas, que en este caso son PREROUTING y OUTPUT, ambas de la tabla nat. Asímismo, también es válido en cualquier cadena creada por el usuario, siempre que sea llamada por una de las anteriores cadenas. Y en cuanto a las posibles opciones, se reducen a una.
Table 6-20. Objetivo REDIRECT
Opción | --to-ports |
Ejemplo | iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080 |
Descripción | La opción --to-ports especifica el puerto o rango de puertos de destino que se debe usar. Sin esta opción, el puerto de destino nunca se modifica. Si deseamos especificar un solo puerto, escribiremos --to-ports 8080, mientras que si deseamos un rango de puertos escribiremos --to-ports 8080-8090; en este último caso le estamos indicando al objetivo REDIRECT que redirija los paquetes a los puertos comprendidos entre el 8080 y el 8090. Como supondrás, esta opción sólo está disponible en aquellas reglas que especifiquen el protocolo TCP o bien el UDP con la comparación --protocol, puesto que no tendría sentido en ningún otro lugar. |
El objetivo REJECT (rechazar) funciona básicamente igual que el objetivo DROP, aunque en este caso sí que se devuelve un mensaje de error al host que envió el paquete bloqueado. El objetivo REJECT, hoy por hoy, sólo es válido en las cadenas INPUT, FORWARD y OUTPUT o sus "sub-cadenas"; después de todo, son las únicas cadenas donde tiene sentido utilizar este objetivo. De momento sólo hay una opción que modifique su forma de trabajar, pero en cambio tiene un montón de variables dónde escoger (la mayoría son fáciles de entender, siempre que tengas un conocimiento básico sobre TCP/IP).
Table 6-21. Objetivo REJECT
Opción | --reject-with |
Ejemplo | iptables -A FORWARD -p TCP --dport 22 -j REJECT --reject-with tcp-reset |
Descripción | Esta opción le indica a REJECT qué respuesta devolver al host que envía el paquete que estamos rechazando. Una vez tenemos un paquete que coincide con la comparación de una regla en la que hemos especificado este objetivo, lo primero que hara nuestro host es enviar la respuesta asociada y entonces se desechará el paquete, tal como lo desecharía el objetivo DROP. Hoy por hoy tenemos disponibles los siguientes tipos de rechazo: icmp-net-unreachable, icmp-host-unreachable, icmp-port-unreachable, icmp-proto-unreachable, icmp-net-prohibited y icmp-host-prohibited. El mensaje de error por defecto que se devuelve al host es port-unreachable. Todos los mensajes anteriores son mensajes de error ICMP y pueden definirse a tu gusto. Puedes encontrar información acerca de sus variados propósitos en el apéndice Tipos ICMP. También tenemos la opción echo-reply, aunque sólo se puede usar con reglas que capten paquetes ICMP ping [cuando el host A hace "ping" sobre el host B, lo que intenta saber es si B está disponible, si (en principio) podría contactar con él]. Por último hay una opción más llamada tcp-reset, que sólo puede usarse junto al protocolo TCP. Esta opción le dice a REJECT que envíe un paquete TCP RST como respuesta. Los paquetes TCP RST se emplean para cerrar de una forma elegante conexiones TCP abiertas. Si quieres saber más sobre TCP RST léete este documento: RFC 793 - Protocolo de Control de Transmisiones. Tal como se describe en el manual de iptables (man iptables), el principal uso de esta opción es bloquear sondeos (pruebas) de identificación, cosa que ocurre frecuentemente al enviar correo a servidores de correo mal configurados, que de otra forma no aceptarán tu correo. |
El objetivo RETURN hará que el paquete que está atravesando una cadena pare allí donde se encuentre con el objetivo; si está en una "sub-cadena", el paquete continuará atravesando la cadena superior desde donde la dejó; si, por el contrario, es una cadena principal (tal como la cadena INPUT), se ejecutará la política por defecto sobre el paquete. La política por defecto normalmente está definida como ACCEPT, DROP o algo similar.
Por ejemplo, un paquete entra en la cadena INPUT y llega a una regla en la que coincide con su comparación y que tiene definida la acción --jump CADENA_DE_EJEMPLO como objetivo; como consecuencia el paquete empezará a atravesar la CADENA_DE_EJEMPLO hasta que llegue a una regla donde coincida con la comparación y cuyo objetivo sea --jump RETURN; entonces volverá a la cadena INPUT y seguirá desde la regla siguiente a la que produjo el salto. Otro ejemplo sería que el paquete llegara a una regla de la cadena INPUT y se le aplicara la acción --jump RETURN, a consecuencia de lo cual se le aplicaría inmediatamente la política por defecto y abandonaría esta cadena, para seguir por el resto de cadenas de la tabla, si las hay.
El objetivo SNAT se emplea para efectuar las traducciones de dirección de red de origen (Source Network Address Translation), lo cual implica que este objetivo reescribirá la dirección IP de origen en la cabecera IP del paquete (ésto es deseable cuando varios hosts tienen que compartir una conexión a Internet). Así pues, podemos activar el reenvío de paquetes IP a nivel de núcleo y escribir una regla SNAT que cambiará la dirección IP de origen de todos los paquetes que salgan de la red local, por la dirección IP de origen de nuestra conexión a Internet. Si no se efectuara esta traducción, el mundo exterior no sabría dónde enviar los paquetes de respuesta, puesto que la mayoría de las redes internas utilizan las direcciones IP especificadas por el IANA para las redes locales. Si los paquetes llegaran tal cual, nadie sabría quién los ha enviado. El objetivo SNAT efectúa todas las traducciones necesarias para llevar a cabo esa tarea, haciendo que todos los paquetes que salgan de la red local parezca que salen de un host concreto (por ej. el cortafuegos).
El objetivo SNAT sólo es válido en la tabla nat y dentro de la cadena POSTROUTING. Sólo el primer paquete de una conexión es modificado por SNAT, después del cual todos los paquetes pertenecientes a la misma conexión serán modificados de la misma manera que el primero: el primer paquete llega al cortafuegos y entra en la tabla nat, dónde pasa en primer lugar por la cadena PREROUTING y se le modifica la dirección de destino con DNAT; a continución llega a la cadena POSTROUTING y se le modifica la dirección de origen con SNAT; después sigue su curso a través del resto de tablas, cadenas y reglas; en cambio el segundo y siguientes paquetes del mismo flujo ni siquiera tocan la tabla nat, sinó que se les aplican directamente las mismas traducciones que al primer paquete. Entre otras razones, es por esta forma de trabajar de la tabla nat por lo que no se recomienda filtrar en élla.
Table 6-22. Objetivo SNAT
Opción | --to-source |
Ejemplo | iptables -t nat -A POSTROUTING -p tcp -o eth0 -j SNAT --to-source 194.236.50.155-194.236.50.160:1024-32000 |
Descripción | La opción --to-source se emplea para especificar qué dirección origen debe utilizar el paquete. La forma más simple de usar esta opción es indicar la dirección IP que deseamos utilizar como dirección IP de origen en las cabeceras IP. Si desearamos balancear la carga entre varias direcciones IP, podemos utilizar un rango separado por un guión. En el caso del ejemplo anterior el rango se presenta como: 194.236.50.155-194.236.50.160. Considerando este rango, la dirección IP de origen de cada flujo que creemos será asignada aleatoriamente a cualquier dirección de las que comprenda el rango y todos los paquetes de cada flujo particular usarán siempre la misma IP; es decir, en el momento de abrir una conexión se crea un flujo de datos al que se le asignará una dirección IP de origen del rango y todos los paquetes de ese flujo tendrán la misma dirección IP de origen; cuando se cree otro flujo se le asignará otra IP que compartirán todos los paquetes del flujo. También podemos especificar a SNAT un rango de puertos, con lo cual todos los puertos de origen serán confinados a los puertos indicados. En el ejemplo anterior esta característica se indica mediante un rango después de "dos puntos", es decir, ":1024-32000". Pero todo ésto sólo es válido si en alguna parte de la comparación se ha especificado -p tcp o -p udp. Además, iptables siempre intentará evitar la alteración de un puerto, pero si dos hosts intentan usar los mismos puertos, iptables le asignará otro puerto a uno de ellos. Si no se especifica ningún rango de puertos, entonces todos los puertos por debajo del 512 se asignarán a otros puertos por debajo del 512 (siempre que sea necesario, claro). De la misma manera, todos los que estén entre los puertos 512 y 1023 serán asignados a puertos por debajo del 1024. Al resto de puertos se les asignará un valor de 1024 o superior. Tal como ya se ha dicho, iptables intentará mantener el puerto origen usado por la estación de trabajo que crea la conexión. Además, fíjate que todo ésto no hace referencia en ningún momento a los puertos de destino, por lo que si un cliente intenta establecer contacto con un servidor HTTP que está fuera del cortafuegos, no se le asignará al puerto FTP control. |
El objetivo TOS se emplea para establecer el campo Tipo de Servicio (Type of Service) de la cabecera IP. Este campo tiene un tamaño de 8 bits y se usa para ayudar a direccionar (enrutar) los paquetes. Éste es uno de los campos que pueden usarse directamente en iproute2 y su subsistema de políticas de enrutado. Vale la pena destacar que si controlas varios cortafuegos y enrutadores separados, ésta es la única manera de difundir información de encaminamiento (enrutado) junto a los paquetes que circulan entre esos enrutadores y cortafuegos. Como ya se ha comentado, el objetivo MARK (que establece una "MARKa" asociada a un paquete específico) sólo está disponible dentro del núcleo y no se puede enviar junto con el paquete. Si necesitas enviar información de enrutado con un paquete o flujo específicos, debes recurrir al campo TOS, pues se diseñó para éso.
En la actualidad hay muchos enrutadores en Internet que trabajan muy mal con este tema, por lo que puede ser bastante inútil intentar modificar el campo TOS antes de enviar los paquetes a Internet. Como mucho los enrutadores no prestarán atención al campo TOS. En el peor de los casos, lo leerán y harán alguna cosa incorrecta. Sin embargo, tal como se ha dicho antes, el campo TOS puede ser muy útil si tienes una WAN (Red de Área Extensa) o una LAN (Red de Área Local) de dimensiones respetables y con múltiples enrutadores. De hecho tienes la posibilidad de darle a los paquetes diferentes encaminamientos y preferencias, basándote en el valor de su TOS (aunque ésto sólo puedas tenerlo bajo control en tu propia red).
El objetivo TOS sólo es capaz de establecer valores o nombres específicos a los paquetes. Estos valores predefinidos se pueden encontrar en los archivos del "kernel include" (ficheros de código fuente del núcleo), o más exactamente en el archivo Linux/ip.h. Las razones son muchas y de hecho no deberías necesitar ningún otro valor; sin embargo, hay formas de superar esta limitación: para evitar la limitación de sólo poder establecer valores nominales (con nombres) a los paquetes, puedes usar el parche FTOS disponible en Paksecured Linux Kernel patches, web mantenida por Matthew G. Marsh; sin embargo, ¡sé extremadamente cauteloso con este parche!, pues nunca deberías tener la necesidad de utilizar ningún valor aparte de los valores por defecto, a excepción de casos extremos. |
Ten en cuenta que este objetivo sólo es válido dentro de la tabla mangle y no puede usarse fuera de élla. |
También es importante que entiendas que algunas viejas versiones de iptables (1.2.2 o anteriores) proporcionan una implementación incompleta de este objetivo y no corrigen la suma de comprobación (checksum) del paquete a la hora de modificarlo, por lo que generan mal los paquetes y como resultado necesitan una retransmisión. Ésto lo más probable es que obligue a una nueva modificación y con éllo que el ciclo vuelva a empezar, dando como resultado que la conexión nunca funcione. |
El objetivo TOS sólo tiene la opción que explico a continuación.
Table 6-23. Objetivo TOS
Opción | --set-tos |
Ejemplo | iptables -t mangle -A PREROUTING -p TCP --dport 22 -j TOS --set-tos 0x10 |
Descripción | Esta opción le dice al procedimiento de modificación TOS qué valor establecer en los paquetes que coincidan con el filtro. Este valor es numérico (hexadecimal o decimal). Como el valor TOS tiene 8 bits, el número estará comprendido entre 0 y 255 (en hexadecimal entre 0x00 y 0xFF). Recuerda que en el objetivo TOS estándar estás limitado a los valores nominales (con nombre) disponibles, que deberían estar más o menos estandarizados. Estos valores estándar son: Minimize-Delay [minimizar el retardo] (valor decimal/dec 16, valor hexadecimal/hex 0x10), Maximize-Throughput [maximizar el rendimiento] (valor dec 8, valor hex 0x08), Maximize-Reliability [maximizar la fiabilidad] (valor dec 4, valor hex 0x04), Minimize-Cost [minimizar el coste] (valor dec 2, valor hex 0x02) ó Normal-Service [servicio normal] (valor dec 0, valor hex 0x00). El valor por defecto en la mayoría de paquetes es Normal-Service, ó 0. Además, obviamente puedes utilizar los nombres en lugar de los valores hexadecimales (y viceversa) para establecer el valor TOS; sin embargo, normalmente se recomienda utilizar el nombre, pues los valores asociados con los nombres pueden cambiar en el futuro. Para ver una lista completa de los "valores descriptivos", ejecuta en la línea de comandos: iptables -j TOS -h. Esta lista se considera completa en la versión 1.2.5 de iptables y debería seguir así por un tiempo. |
Este objetivo necesita del parche TTL del patch-o-matic, en el directorio raíz, en http://www.netfilter.org/documentation/index.html#FAQ - Las Frequently Asked Questions (Preguntas Frecuentes) oficiales de Netfilter. Éste es también un buen lugar de comienzo cuando empiezas a preguntarte qué hacen iptables y Netfilter.. |
El objetivo TTL se usa para modificar el campo Time To Live de la cabecera IP. Una aplicación útil para ésto puede ser cambiar todos los valores Time To Live al mismo valor en todos los paquetes dirigidos al exterior de la red. Una razón para necesitar ésto es que tengas un ISP abusivo que no te permita tener más de una máquina conectada a la misma conexión de Internet, y que lo persiga activamente. Estableciendo todos los valores TTL al mismo valor le harás un poco más difícil (al ISP) darse cuenta de lo que estás haciendo. Así pues, podemos establecer el valor TTL de todos los paquetes de salida a un valor estandarizado, como 64, que es el valor estándar del núcleo de Linux.
Para más información sobre cómo establecer el valor por defecto usado por Linux, léete el ip-sysctl.txt, que puedes encontrar en el apéndice Otras fuentes y enlaces.
El objetivo TTL sólo es válido en la tabla mangle y en ninguna tabla más. De momento tiene 3 opciones que describo a continuación.
Table 6-24. Objetivo TTL
Opción | --ttl-set |
Ejemplo | iptables -t mangle -A PREROUTING -i eth0 -j TTL --ttl-set 64 |
Descripción | La opción --ttl-set le dice al objetivo TTL qué valor TTL establecer en el paquete. Un valor de referencia bastante correcto podría estar alrededor de 64, un valor ni muy alto ni muy bajo. Lo que no debes hacer es establecer un valor demasiado alto, pues puede afectar a tu red local y además resulta un poco inmoral, puesto que el paquete puede empezar a rebotar entre dos enrutadores mal configurados y cuanto más alto sea el TTL, más ancho de banda consumirá innecesariamente en un caso así. Este objetivo puede emplearse para limitar lo alejados que pueden estar nuestros clientes, como por ej. en el caso de los servidores DNS, dónde no queremos que los clientes estén muy lejos. |
Opción | --ttl-dec |
Ejemplo | iptables -t mangle -A PREROUTING -i eth0 -j TTL --ttl-dec 1 |
Descripción | La opción --ttl-dec hace que se decremente el tiempo de vida del paquete una cantidad equivalente al valor indicado tras la opción (en el ejemplo, el decremento indicado es de uno). Así pues, si el TTL de un paquete entrante es de 53 y hemos establecido un decremento --ttl-dec 3, el paquete verá reducido su TTL hasta el valor 49. La razón de esta diferencia estriba en que el código de gestión de redes reducirá automáticamente el TTL en un punto, por lo que el paquete sufrirá un decremento de 3+1, desde 53 hasta 49. Mediante este sistema podemos limitar lo alejados que pueden estar los usuarios de nuestros servicios. Por ejemplo, los usuarios siempre deben usar un DNS cercano, y en consecuencia podemos comparar todos los paquetes que dejen nuestro servidor DNS y reducir el TTL en varias unidades. Por supuesto, la opción --set-ttl es más adecuada para este uso. |
Opción | --ttl-inc |
Ejemplo | iptables -t mangle -A PREROUTING -i eth0 -j TTL --ttl-inc 1 |
Descripción | La opción --ttl-inc es la opuesta a la anterior, es decir, se incrementa el TTL en una cantidad expresada a continuación de la opción. Ten en cuenta que en este caso el código de gestión de redes también actúa automáticamente reduciendo el TTL en 1, por lo que si escribimos --ttl-inc 4, un paquete entrante con un TTL de 53 dejará el host con un valor TTL de 56, ésto es, 53+4-1. Con esta opción podemos hacer nuestro cortafuegos un poco más invisible a los trazadores de rutas (traceroutes), entre otras cosas: al establecer el valor TTL de los paquetes entrantes a un valor más alto, conseguimos que el cortafuegos se oculte a los trazadores. Los trazadores de rutas son utilidades amadas y odiadas al mismo tiempo, puesto que facilitan información excelente sobre problemas con las conexiones y dónde ocurren, si bien al mismo tiempo le ofrecen al hacker/cracker que te haya localizado muy buena información sobre tus conexiones con el exterior. Para ver un buen ejemplo de cómo puedes usarlo, mira el script Ttl-inc.txt. |
Este objetivo se emplea para proporcionar capacidades de registro en el espacio de usuario a los paquetes que concuerden. Si un paquete coincide con la comparación del filtro (de la regla) y se ha establecido el objetivo ULOG, la información del paquete es difundida mediante una "multidifusión" (multicast), junto con el paquete entero, a través de una conexión virtual de red (netlink socket). A partir de entonces, uno o varios procesos de espacio de usuario pueden subscribirse a varios grupos de multidifusión y recibir el paquete. Ésta es una capacidad más completa y sofisticada de registro que hasta ahora sólo utilizan iptables y Netfilter y que tiene mucha más capacidad para el registro de paquetes. Este objetivo nos permite registrar información en bases de datos MySQL, entre otras, haciendo más fácil la búsqueda de paquetes específicos y el agrupamiento de entradas de registro. Puedes encontrar las aplicaciones de espacio de usuario de ULOGD en Página del proyecto ULOGD.
Table 6-25. Objetivo ULOG
Opción | --ulog-nlgroup |
Ejemplo | iptables -A INPUT -p TCP --dport 22 -j ULOG --ulog-nlgroup 2 |
Descripción | La opción --ulog-nlgroup le dice al objetivo ULOG a qué grupo de conexión de red enviar el paquete. Existen 32 grupos de conexión de red, que se especifican con un núemero del 1 al 32, o sea que si queremos contactar con el grupo 5, simplemente escribiremos --ulog-nlgroup 5. El grupo por defecto es el 1. |
Opción | --ulog-prefix |
Ejemplo | iptables -A INPUT -p TCP --dport 22 -j ULOG --ulog-prefix "SSH connection attempt: " |
Descripción | La opción --ulog-prefix trabaja igual que el prefijo del objetivo LOG estándar: esta opción le añade un prefijo definido por el usuario a todas las entradas de registro. Este prefijo puede tener hasta 32 caracteres y es realmente útil para diferenciar distintos mensajes de registro y de dónde vienen. |
Opción | --ulog-cprange |
Ejemplo | iptables -A INPUT -p TCP --dport 22 -j ULOG --ulog-cprange 100 |
Descripción | La opción --ulog-cprange le indica a ULOG cuántos bytes del paquete enviar al demonio de espacio de usuario de ULOG. Si especificamos un valor de 100, copiaremos 100 bytes del total del paquete al espacio de usuario, lo cual en principio incluirá la cabecera completa, más algunos datos básicos del paquete. Si por el contrario especificamos 0, se copiará el paquete entero al espacio de usuario sin importar su tamaño. El valor por defecto es 0, y por lo tanto se copiará el paquete completo al espacio de usuario. |
Opción | --ulog-qthreshold |
Ejemplo | iptables -A INPUT -p TCP --dport 22 -j ULOG --ulog-qthreshold 10 |
Descripción | Esta opción indica el número de paquetes a poner en cola dentro del núcleo antes de enviar realmente los datos al espacio de usuario. Por ejemplo, si establecemos un umbral de 10 como en el ejemplo, el núcleo acumulará 10 paquetes antes de transmitirlos al espacio de usuario mediante un sólo mensaje multi-parte. El valor por defecto es 1 a causa de la compatibilidad con versiones más antiguas (el demonio del espacio de usuario no sabía cómo manejar mensajes multi-parte). |