Introducción a NAT

La Traducción de Direcciones de Red, o NAT (Network Address Translation), es un sistema que se utiliza para asignar una red completa (o varias redes) a una sola dirección IP. NAT es necesario cuando la cantidad de direcciones IP que nos haya asignado nuestro proveedor de Internet sea inferior a la cantidad de ordenadores que queramos que accedan a Internet. NAT se describe en el RFC 1631.
NAT nos permite aprovechar los bloques de direcciones reservadas que se describen en el RFC 1918. Generalmente, una red interna se suele configurar para que use uno o más de estos bloques de red. Estos bloques son:

10.0.0.0/8 (10.0.0.0 - 10.255.255.255)
172.16.0.0/12 (172.16.0.0 - 172.31.255.255)
192.168.0.0/16 (192.168.0.0 - 192.168.255.255)

Un sistema OpenBSD configurado para NAT tendrá como mínimo dos adaptadoras de red, una para Internet y la otra para la red interna. NAT se encargará de traducir los requerimientos desde la red interna, de modo que parezca que todos provienen del sistema OpenBSD en el que se encuentra configurado NAT.

Cómo Funciona NAT

Cuando un cliente en la red interna contacta con un máquina en Internet, envía paquetes IP destinados a esa máquina. Estos paquetes contienen toda la información de direccionamiento necesaria para que puedan ser llevados a su destino. NAT se encarga de estas piezas de información:
Dirección IP de origen (por ejemplo, 192.168.1.35)
Puerto TCP o UDP de origen (por ejemplo, 2132)
Cuando los paquetes pasan a través de la pasarela de NAT, son modificados para que parezca que se han originado y provienen de la misma pasarela de NAT. La pasarela de NAT registra los cambios que realiza en su tabla de estado, para así poder: a) invertir los cambios en los paquetes devueltos, y b) asegurarse de que los paquetes devueltos pasen a través del cortafuegos y no sean bloqueados. Por ejemplo, podrían ocurrir los siguientes cambios:

IP de origen: sustituida con la dirección externa de la pasarela (por ejemplo, 24.5.0.5)
Puerto de origen: sustituido con un puerto no en uso de la pasarela, escogido aleatoriamente (por ejemplo, 53136)
Ni la máquina interna ni el anfitrión de Internet se dan cuenta de estos pasos de traducción. Para la máquina interna, el sistema NAT es simplemente una pasarela a Internet. Para el anfitrión de Internet, los paquetes parecen venir directamente del sistema NAT; ni siquiera se da cuenta de que existe la estación interna.
Cuando el anfitrión de Internet responde a los paquetes internos de la máquina, los direcciona a la IP externa de la pasarela de NAT (24.5.0.5) y a su puerto de traducción (53136). La pasarela de NAT busca entonces en la tabla de estado para determinar si los paquetes de respuesta concuerdan con alguna conexión establecida. Entonces encontrará una única concordancia basada en la combinación de la dirección IP y el puerto, y esto indica a PF que los paquetes pertenecen a una conexión iniciada por la máquina interna 192.168.1.35. Acto seguido PF realiza los cambios opuestos a los que realizó para los paquetes salientes, y reenvía los paquetes de respuesta a la máquina interna.
La traducción de paquetes ICMP ocurre de forma parecida, pero sin la modificación del puerto de origen.
Activación de NAT
Para activar NAT en una pasarela de OpenBSD, además de activar PF, también hay que activar el reenvío de paquetes IP (IP forwarding):
# sysctl net.inet.ip.forwarding=1
# sysctl net.inet6.ip6.forwarding=1 (si se usa IPv6)
Para que este cambio sea permanente, hay que añadir las siguientes líneas al fichero /etc/sysctl.conf:
net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1
Estas líneas ya existen en la instalación determinada, pero como comentarios (prefijadas con #). Hay que quitar el signo # y guardar el fichero. El reenvío de IP se activará cuando se reinicie la máquina.
Configuración de NAT
El formato general para las reglas de NAT en /etc/pf.conf es parecido al siguiente:
nat on extif [af] from src_addr [port src_port] to \
dst_addr [port dst_port] -> ext_addr
extif
El nombre de la interfaz de red.
af
La familia de direcciones, que será inet para IPv4 ó inet6 para IPv6. PF suele ser capaz de determinar este parámetro basándose en la dirección (o direcciones) de origen/destino.
src_addr
La dirección de origen (interna) de los paquetes que vayan a ser traducidos. La dirección de origen se puede especificar como:
Una dirección IPv4 ó IPv6 única.
Un bloque de red del esquema de «Enrutamiento de Inter-Dominios sin Clases» (CIDR).
Un «Nombre de Dominio Totalmente Cualificado» (FQDN) que se resolverá por el «Servicio de Nombres de Dominio» (DNS) cuando se cargue el grupo de reglas. Todas las direcciones IP resultantes se sustituirán dentro de la regla.
El nombre de una interfaz de red. Cualquier dirección IP asignada a la interfaz será sustituida dentro de la regla cuando se carguen las reglas.
El nombre de una interfaz de red seguida de una máscara de red como sigue: /netmask (por ejemplo /24). Cada dirección IP en la interfaz se combina con la máscara de red para formar un bloque de red CIDR que se sustituye dentro de la regla.
El nombre de una interfaz de red seguida de cualquiera de estos modificadores:
:network - expande a un bloque de red CIDR (ejemplo: 192.168.0.0/24)
:broadcast - expande a la dirección de difusión de la red (ejemplo: 192.168.0.255)
eer - expande a la dirección IP del otro extremo en una conexión punto a punto
Además, el modificador :0 puede ser añadido tanto al nombre de la interfaz or a cualquier de los modificadores anteriores para indicar que PF no debe incluir direcciones IP de alias en la expansión. Estos modificadores también pueden ser usados cuando la interfaz esté enre paréntesis. Ejemplo: fxp0:network:0
Una tabla.
Cualquiera de los anteriores en negación, usando el modificador ! ("not").
Un grupo de direcciones que usen una lista.
La clave any para indicar todas las direcciones.
src_port
El puerto de origen en la capa Layer 4 de la cabecera del paquete. Los puertos se pueden especificar como:
Un número entre 1 y 65535
Un nombre de servicio válido de /etc/services
Un grupo de puertos que usen una lista
Un indicador de campo:
!= (no es igual que)
< (menor que)
> (mayor que)
<= (menor o igual que)
>= (mayor o igual que)
>< (intervalo)
<> (intervalo inverso)
Los dos últimos son operadores binarios (toman dos argumentos) y no incluyen los argumentos en el campo.
: (intervalo inclusivo)
El operador de intervalo inclusivo también es un operador binario e incluye el argumento en el intervalo.
La opción port no se suele usar en las reglas de nat por que el objetivo suele ser traducir las direcciones de todo el tráfico sin tener en cuenta el puerto, o los puertos, que se estén utilizando.
dst_addr
La dirección de destino de los paquetes que hay que traducir. La dirección de destino se especifica del mismo modo que la dirección de origen.
dst_port
El puerto de destino en la capa Layer 4 de la cabecera del paquete. Este puerto se especifica del mismo modo que el puerto de origen.
ext_addr
La dirección externa (la traducción) en la pasarela NAT a la que se traducirán los paquetes. La dirección externa se puede especificar como:
Una dirección IPv4 ó IPv6 única.
Un bloque de red CIDR.
Un «Nombre de Dominio Totalmente Cualificado» (FQDN) que se resolverá por el «Servicio de Nombres de Dominio» (DNS) cuando se cargue el grupo de reglas.
El nombre de la interfaz de red externa. Cualquier dirección IP asignada a la interfaz será sustituida dentro de la regla cuando se carguen las reglas.
El nombre de la interfaz de red externa entre paréntesis. De este modo se instruye a PF para que actualice la regla si la dirección, o direcciones, IP en dicha interfaz cambia. Es de gran utilidad cuando la interfaz externa obtiene su dirección IP por medio de DHCP o de una conexión tipo dial-up, ya que no hay que volver a cargar el grupo de reglas cada vez que cambie la dirección.
El nombre de una interfaz de red seguida por cualquiera de los siguientes modificadores:
:network - expande al bloque de red CIDR (ejemplo: 192.168.0.0/24)
eer - expande a la dirección IP del extremo en una conexión punto a punto
Además, el modificador :0 puede ser añadido tanto al nombre de la interfaz o a cualquier de los modificadores anteriores para indicar a PF no debe incluir direcciones IP de alia en la expansión. Estos modificadores también pueden ser usados cuando la interfaz está encerrada entre paréntesis. Ejemplo: fxp0:network:0
Un grupo de direcciones que usen una lista.
Esto nos llevaría a una forma muy básica de la línea, que quedaría parecida a la siguiente:
nat on tl0 from 192.168.1.0:network to any -> 24.5.0.5
Esta regla indica que hay que realizar NAT en la interfaz tl0 para cualquier paquete que venga de 192.168.1.0/24, y sustituir la dirección IP de origen con 24.5.0.5.
Aunque la regla anterior es correcta, la forma no es la recomendable. El mantenimiento podría resultar difícil ya que cualquier cambio de los números de la red externa o interna requeriría que se cambiara la línea. Cómparese con la siguiente regla (tl0 es externa y dc0 interna), que es más fácil de mantener:
nat on tl0 from dc0:network to any -> tl0
La ventaja debería ser obvia: podemos cambiar la dirección IP de cualquiera de las interfaces sin cambiar esta regla.
Cuando se especifica un nombre de interfaz para la dirección de traducción, como en el ejemplo anterior, la dirección IP se determina en el momento de carga de pf.conf, no sobre la marcha. Si se está usando DHCP para configurar la interfaz externa, esto puede representar un problema, ya que si la dirección IP asignada cambiara, entonces NAT seguiría traduciendo los paquetes salientes usando la dirección IP antigua. Como resultado, las conexiones salientes dejarían de funcionar. Para evitarlo, se puede indicar a PF que actualice automáticamente la dirección de traducción poniendo entre paréntesis el nombre de la interfaz:
nat on tl0 from dc0:network to any -> (tl0)
Este método funciona para traducir tanto direcciones IPv4 como IPv6.

Asignación Bidireccional (asignación 1:1)

Se puede establecer una asignación de tipo bidireccional usando la regla binat. Una regla binat establece una asignación de uno por uno entre la dirección IP interna y la dirección externa. Esto puede ser útil, por ejemplo, para colocar un servidor de web en la red interna con su propia dirección IP externa. Las conexiones desde Internet hacia la dirección externa se traducirán a la dirección interna, y las conexiones desde el servidor de web (como los requerimientos de DNS) se traducirán a la dirección externa. Los puertos TCP y UDP nunca se modifican con las reglas binat como se modifican con las reglas nat.
Ejemplo:
web_serv_int = "192.168.1.100"
web_serv_ext = "24.5.0.6"

binat on tl0 from $web_serv_int to any -> $web_serv_ext
Excepciones a las Reglas de Traducción
Se pueden hacer excepciones a las reglas de traducción usando la clave no. Así, el ejemplo de NAT anterior se modificaría del siguiente modo:
no nat on tl0 from 192.168.1.10 to any
nat on tl0 from 192.168.1.0/24 to any -> 24.2.74.79
Y entonces los paquetes de toda la red 192.168.1.0/24 se traducirían a la dirección externa 24.2.74.79, a excepción de 192.168.1.10.
Nótese que la primera regla que concuerde será la que se aplique; si es una regla con la clave no, entonces el paquete no se traducirá. La clave no también se puede usar con reglas binat y rdr.

Comprobación del Estado de NA

Para ver las traducciones de NAT activas se usa pfctl(8) con la opción y el argumento -s state. Esta opción muestra un listado de todas las sesiones de NAT actuales:
# pfctl -s state
fxp0 TCP 192.168.1.35:2132 -> 24.5.0.5:53136 -> 65.42.33.245:22 TIME_WAIT:TIME_WAIT
fxp0 UDP 192.168.1.35:2491 -> 24.5.0.5:60527 -> 24.2.68.33:53 MULTIPLE:SINGLE
La explicación de esto (sólo de la primera línea) es:
fxp0
Indica la interfaz a la que está asociado el estado. Aparecerá la palabra self si el estado es floating.
TCP
El protocolo que está usando la conexión.
192.168.1.35:2132
La dirección IP (192.168.1.35) de la máquina en la red interna. El puerto de origen (2132) se muestra después de la dirección. Ésta también es la dirección que se sustituye en la cabecera IP.
24.5.0.5:53136
La dirección IP (24.5.0.5) y el puerto (53136) en la pasarela a la que se están traduciendo los paquetes.
65.42.33.245:22
La dirección IP (65.42.33.245) y el puerto (22) al que se está conectando la máquina interna.
TIME_WAIT:TIME_WAIT
Indica el estado en el que PF cree que se encuentra la conexión TCP.

Zirkua [editorial RA-MA]