De manera que ahora sabemos cómo elegir los paquetes que queremos modificar. Para completar nuestra regla, necesitamos decirle al núcleo exactamente qué queremos que haga con los paquetes.
Quiere hacer Source NAT; cambiar la dirección de origen de las conexiones a algo diferente. Esto se hace en la cadena POSTROUTING, justo antes de que sea enviado. Este es un detalle importante, ya que significa que cualquier otro servicio de la máquina Linux (encaminamiento, filtrado de paquetes) verá el paquete sin cambiar. También significa que se puede utilizar la opción «-o» (interfaz de salida).
El Source NAT se especifica indicando «-j SNAT», y la opción «--to-source» especifica una dirección IP, un rango de direcciones IP, y un puerto o rango de puertos opcionales (sólo con los protocolos UDP y TCP).
## Cambiar la dirección de origen por 1.2.3.4
# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4
## Cambiar la dirección de origen a 1.2.3.4, 1.2.3.5 o 1.2.3.6
# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4-1.2.3.6
## Cambiar la dirección de origen por 1.2.3.4, puertos 1-1023
# iptables -t nat -A POSTROUTING -p tcp -o eth0 -j SNAT --to 1.2.3.4:1-1023
Hay un caso especializado de Source NAT denominado «enmascaramiento» (masquerading): sólo debería ser usado para direcciones IP asignadas de forma dinámica, tales como las de conexiones por llamada estándar (para direcciones IP estáticas, utilize el SNAT descrito anteriormente).
No es necesario escribir la dirección de origen de forma explícita con el enmascaramiento: utilizará la dirección de origen de la interfaz por la que el paquete está saliendo. Pero más importante aún, si el enlace cae, las conexiones (que se iban a perder de todas maneras) se olvidan, lo que significa que habrá menos follón cuando la conexión vuelva a la normalidad con una IP diferente.
## Enmascarar todo lo que salga por ppp0.
# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
Esto se hace en la cadena PREROUTING, según entra el paquete; esto significa que cualquier otro servicio de la máquina con Linux (encaminamiento, filtrado de paquetes) verá el paquete yendo a su destino «real» (el definitivo). Esto significa que se puede utilizar la opción «-i» (interfaz de entrada).
Para alterar el destino de un paquete generado de forma local (en la máquina que hace el NAT), se debe usar la cadena OUTPUT, pero esto es más inusual.
Destination NAT se especifica utilizando «-j DNAT», y la opción «--to-destination» especifica una dirección IP, un rango de direcciones IP, y un puerto o rango de puertos opcionales (sólo para los protocolos UDP y TCP).
## Cambia la dirección de destino por 5.6.7.8
# iptables -t nat -A PREROUTING -i eth1 -j DNAT --to 5.6.7.8
## Cambia la dirección de destino por 5.6.7.8, 5.6.7.9 o 5.6.7.10.
# iptables -t nat -A PREROUTING -i eth1 -j DNAT --to 5.6.7.8-5.6.7.10
## Cambia la dirección de destino del tráfico web por 5.6.7.8,
## puerto 8080.
# iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth1 \
-j DNAT --to 5.6.7.8:8080
## Redirige los paquetes locales que van a 1.2.3.4 hacia el dispositivo
## loopback.
# iptables -t nat -A OUTPUT -d 1.2.3.4 -j DNAT --to 127.0.0.1
Hay un caso especializado de Destination NAT llamado redirección: es una simple conveniencia que es exactamente lo mismo que hacer DNAT, pero con la dirección de la interfaz de entrada.
## Envía el tráfico que entra dirigido al puerto 80 (web) a nuestro
## proxy squid (transparente)
# iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 \
-j REDIRECT --to-port 3128
Hay algunas sutilezas de NAT con las que la mayoría de la gente no tendrá que enfrentarse nunca. Las he documentado aquí para los más curiosos.
Si se da un rango de direcciones IP, la dirección a usar se elegirá basándose en la menos utilizada para las conexiones de las que sabe nuestra máquina. Esto nos permite hacer un balanceo de carga primitivo.
Puede utilizar el objetivo «-j ACCEPT» para dejar que una conexión pase sin que se produzca ninguna conversión NAT.
El comportamiento estándar es alterar la conexión lo menos posible, dentro de los límites de la regla dada por el usuario. Esto significa que no cambiaremos el puerto a menos que nos veamos obligados.
Incluso cuando no se pide NAT para una conexión, puede ser que haya un cambio de puerto de forma implícita, si otra conexión lo está usando ya. Consideremos el caso del enmascaramiento, que es lo más común:
Cuando se produce este cambio implícito de origen, los puertos se dividen en tres clases:
Nunca se hará corresponder un puerto con otro de clase diferente.
Si no hay manera de hacer corresponder una conexión de forma única tal como ha pedido el usuario, será descartada. Esto se aplica también a los paquetes que no pueden ser clasificados como parte de una conexión, porque están malformados, o nos hemos quedado sin memoria, etc.
Podemos tener reglas NAT que asignen paquetes dentro del mismo rango. El código NAT es suficientemente inteligente para evitar colisiones. Por tanto, tener dos reglas que hagan corresponder las direcciones de origen 192.168.1.1 y 192.168.1.2 respectivamente con 1.2.3.4 es correcto.
Aún más, se pueden hacer correspondencias sobre direcciones reales y en uso, siempre y cuándo estas direcciones pasen también a través de nuestra máquina. De manera que si tenemos una red asignada (1.2.3.0/24), pero tenemos una red interna que está usando esas direcciones y otra con Direcciones Privadas de Internet 192.168.1.0./24, podemos hacer NAT con las direcciones de origen 192.168.1.0/24 dentro del rango de la red 1.2.3.0, sin temor a colisiones:
# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 \
-j SNAT --to 1.2.3.0/24
La misma lógica se aplica a las direcciones que usa la propia caja que hace NAT: ésta es la manera en que funciona el enmascaramiento (compartiendo las direcciones de la interfaz entre los paquetes enmascarados y los paquetes «reales» que vienen de la propia máquina).
Aún más, podemos direccionar los mismos paquetes a varios objetivos diferentes, y serán compartidos. Por ejemplo, si no queremos direccionar nada usando 1.2.3.5, podríamos hacer:
# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 \
-j SNAT --to 1.2.3.0-1.2.3.4 --to 1.2.3.6-1.2.3.254
Si se cambia el destino de un paquete generado de forma local (esto es, usando la cadena OUTPUT), y eso hace que el paquete salte a una interfaz diferente, entonces se cambia también la dirección de origen a la de esa interfaz. Por ejemplo, cambiar el destino de un paquete de loopback para que salga por eth0 tendrá como resultado que también se cambie la dirección de origen, 127.0.0.1, por la de eth0. Al contrario que con el resto de cambios, esto se hace de forma inmediata. Naturalmente, ambos cambios son invertidos cuando llega la respuesta del paquete.