Busindre » Blog Archive » Permitir uso de FTP activo detrás de un NAT generado por IPtables

Permitir uso de FTP activo detrás de un NAT generado por IPtables

July 11th, 2008 by Busindre

Una solución muy popular a la hora de usar una máquina GNU/Linux como router para ofrecer conexión a otros ordenadores de la red (hosts), es el uso del firewall iptables, que debido a su funcionalidades con el mecanismo NAT lo hacen muy atractivo para este tipo escenarios. Por defecto, dependiendo de la distro podemos encontrar que los host que están detrás de ese firewall no pueden acceder a servicios FTP en el exterior usando el modo activo (Por defecto) y es lo que vamos a tratar de solucionar, explicar y razonar. Primero debemos tener unos conceptos claros, tanto sobre iptables / Netfilter como sobre el protocolo FTP en su modo activo.

Vamos a entrar en materia, Netfilter es un framework disponible en el kernel de GNU/Linux que nos permite interceptar y manipular paquetes en cualquiera de los diferentes estados de las conexiones, ya que esta integrado a bajo nivel, a nivel de núcleo, como la pila de protocolos TCP/IP. No debemos caer en el error de referirnos a toda la infraestructura ofrecida por el proyecto Netfilter como iptables, no hay que confundir los términos, iptables símplemente es una parte de la totalidad del framework Netfilter. Este componente sin embargo es el más popular de la suite, dicho firewall no solamente filtra paquetes, sino que también puede realizar traducción de direcciones de red (NAT) para IPv4, que es lo que nos viene a interesar en este artículo. Las traducciones realizadas por el mecanismo NAT pueden ser más completas gracias a los módulos que netfilter ofrece. Estos módulos al estar cargados en memoria permiten al kernel de GNU/linux modificar los paquetes que pasen por la pila TCP/IP según se haya programado, que es lo que nos ayudará a solventar ese pequeño problema del uso de FTP (Activo) detrás de un NAT de iptables.

Esquema de red:

Host (192.168.2.19) <------> (192.168.2.33) GNU/Linux (192.168.1.33) <------> (192.168.1.1) Router ADSL

* Host: Cualquier PC detrás de un PC GNU/Linux con iptables que haga NAT.
* Host GNU/Linux: Ordenador que hará de router a los host que estén detrás de el mediante iptables. (Dos tarjetas de red)
* Router ADSL: Un router que sacará las conexiones a Internet, lógicamente tiene su propio programa de NAT que suponemos funciona correctamente, realmente no debemos prestarle atención.

NOTA: En el artículo nos centraremos en la máquina GNU/Linux que hace NAT.

Comandos usados en este escenario para que el ordenador con GNU/Linux haga de router NAT:

# iptables --append FORWARD --in-interface eth0 -j ACCEPT
# iptables --table nat --append POSTROUTING --out-interface wlan0 -j MASQUERADE
# iptables -t nat -A PREROUTING -i wlan0 -p tcp --dport 6891 -j DNAT --to-destination 192.168.2.19

NOTA: Para profundizar sobre como hacer NAT con iptables tenemos estos dos artículos:

Hacer NAT con iptables: http://www.busindre.com/linux-como-router-facil/
Habilitar servicios detrás de NAT: http://www.busindre.com/servidor-linux-a-traves-de-router-pc/

Una vez se tiene el NAT correctamente funcionando, intentaremos conectar desde uno de los hosts a un servidor FTP en la Internet pública.

# ftp dominio.es
Connected to dominio.es.
220 (vsFTPd 2.0.1)
Name (dominio.es:busi): dominio.es
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
500 Illegal PORT command.
ftp: bind: Address already in use
ftp> dir
500 Illegal PORT command.
ftp> bye
221 Goodbye.

Como vemos parece que hay problemas a la hora de ejecutar la transferencia de datos (500 Illegal PORT command.), en este caso, los clientes necesitaríamos usar el modo pasivo para poder hacer uso del servidor FTP. El por qué NO podemos hacer uso del modo activo de FTP recae sobre la propia implementación del programa de NAT (iptables) y los paquetes FTP con directivas PORT. Un NAT correctamente implementado debería ofrecer una conexión FTP en modo activa para sus cliente:

$ ftp dominio.es
Connected to dominio.es.
220 (vsFTPd 2.0.1)
Name (dominio.es:busi): USUARIO
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 PORT command successful. Consider using PASV. <---------------
150 Here comes the directory listing.
drwxr-xr-x 2 1533 1471 4096 Jan 17 2007 cgi-bin
drwxrwxr-x 2 1533 1471 4096 Jan 17 2007 data
drwxrwxr-x 2 1533 1471 4096 Jan 17 2007 errors
drwxrwxr-x 3 1533 1471 4096 Jun 18 16:05 html
drwxr-xr-x 2 0 0 20480 Jul 09 04:07 logs
226 Directory send OK.
ftp>

Vamos a ver en que consiste es problema que parece tener NAT con FTP e intentar solventarlo.

Puerto de Datos (PORT)

En los paquetes FTP enviados por el cliente con instrucciones PORT se especifica el puerto que será usado por dicho cliente en la conexión de datos. Hay valores por defecto tanto para el puerto de usuario como para el del servidor y, bajo circunstancias normales, esta orden y su respuesta no son necesarias, pero eso depende del cliente de FTP usado y su forma de trabajar. Si se usa esta orden, el argumento es la concatenación de una dirección IP (32 bits) y un puerto TCP (16 bits), donde la dirección IP es la del host que conecta al FTP y el puerto indicado es donde está dispuesto a recibir el cliente la transferencia de datos. Este tipo de paquetes tiene la información repartida en campos de 8 bits y el valor de cada campo se transmite como un número decimal (Representado como una cadena de numeros). Los campos están separados por comas.

PORT aaa,bbb,ccc,ddd, ffff,yyy

Donde la dirección del cliente es aaa.bbb.ccc.ddd y el puerto por el que aceptará la transferencia es el resultado de la operación matemática siguiente: (ffff x 256 + yyy). Cada campo es de 8 bits, por lo que tenemos 32 bits para la dirección IP y 16 para el puerto, que es lo que deben de tener según la teoría de direcciones IP y números de puerto.

Al ejecutar un comando bajo una conexión FTP, como puede ser dir, ls, put o cualquier otro, se envía por parte del cliente un paquete usando la orden PORT, indicándole al servidor como antes decíamos, que puerto y dirección IP del cliente esta preparada para recibir el transito de datos.

Ejemplo de paquete FTP con la orden PORT:

Cliente: 192.168.1.33 (Capa 3)
Comando PORT 192,168,1,33,197,188 (Capa aplicación)

De ese paquete se deduce:

Dirección IP PORT: 192.168.1.33
Cálculo de puerto: 197 x 256 + 188 = 50620

El puerto numero 50620 es el puerto destino que usara el servidor FTP para enviar datos al cliente de dirección 192.168.1.33, ya que así se lo han solicitado. Una vez entendido el concepto de PORT, veamos en que falla el NAT de iptables.

Host (192.168.2.19) <------> (192.168.2.33) GNU/Linux (192.168.1.33) <------> INTERNET

La máquina GNU/Linux es la encargada de hacer NAT, por lo tanto las peticiones entrantes que recibe del host 192.168.2.19 las saca por la interfaz que se comunica a Internet mediante la dirección IP 192.168.1.33, pero en el caso de los paquetes FTP PORT solo modifica la dirección de capa 3 del paquete, mientras que la dirección que se especifica dentro del comando PORT no se modifica por iptables (NAT). Veamos un ejemplo de paquete PORT que ha sido recibido por la máquina GNU/Linux desde 192.168.2.19, modificado por iptables (NAT) y enviado por la interfaz 192.168.1.33.

Paquete FTP con la orden PORT:

Cliente: 192.168.1.33 (Capa 3)
Comando PORT 192,168,2,19,197,188 (Capa aplicación)

De ese paquete se deduce:

Dirección IP PORT: 192.168.2.19 <-----
Cálculo de puerto: 197 x 256 + 188 = 50620

El problema es que no se modifica el contenido de la directiva PORT del paquete FTP, la dirección IP (Capa de red) es correcta pero no la de PORT, que debería ser la misma que la usada en la capa 3 (192.168.1.3). Esto origina que el servidor no responda debido a que la dirección IP que le indicamos no es correcta. Esa es la explicación por la que no se puede hacer uso de FTP activo en determinados proxy, firewall, routers,.. es culpa de una implementación de NAT muy pobre o incompleta. Pero esto tiene fácil solución si hablamos de iptables, solo debemos indicarle al firewall, mediante la carga de unos módulos ( ip_conntack_ftp / ip_nat_ftp), que modifique esos campos de los paquetes FTP para que así el servidor pueda responderlos correctamente.

Solución:

# modprobe ip_nat_ftp ip_conntrack_ftp

NOTA: Realmente solo es necesario cargar el modulo ip_conntrack_ftp ya que producirá la carga de los otros módulos restantes de forma automática. Los módulos los encontramos en el directorio del kernel correspondiente a iptables se encuentran en /lib/modules/2.6.*.*/kernel/net/ipv4/netfilter/

¿En que consisten esos módulos de Netfilter?

El modulo ip_conntack_ftp habilita que el firewall identifique los paquetes FTP.

El modulo ip_nat_ftp se encarga, una vez identificado el paquete FTP, de modificar esos campos del paquete (Dirección IP del comando FTP PORT) para que se pueda realizar una conexión FTP sin necesidad de usar el modo pasivo, en resumen, realiza un NAT más eficiente y correcto.

Veamos que otros módulos se cargan al usar modprobe:

# lsmod | grep -i ftp

De no encontrar módulos con el nombre ftp es que no se tiene por defecto activados los módulos anteriores.

# modprobe ip_nat_ftp
# lsmod | grep -i ftp
nf_nat_ftp 6912 0
nf_conntrack_ftp 11776 1 nf_nat_ftp
nf_nat 19116 4 nf_nat_ftp,ipt_REDIRECT,ipt_MASQUERADE,iptable_nat
nf_conntrack 52616 6 nf_nat_ftp,nf_conntrack_ftp,ipt_MASQUERADE,iptable_nat,nf_nat,nf_conntrack_ipv

Esta salida es la de un servidor de NAT que posibilita conexiones FTP en modo activo a través de sus interfaces. Algo parecido es lo que hacen los diferentes routers ADSL (Configurados en modo multipuesto) que usan NAT, encontraremos unos pocos que no tienen un programa de NAT decente instalado y por lo tanto exigen a los usuarios de su LAN a usar FTP de modo pasivo si quieren usar dicho protocolo. Para terminar y como prueba de concepto, dejamos dos capturas del tráfico FTP saliente de la interfaz 192.168.1.3 de la máquina GNU/Linux (NAT), donde veremos lo comentado anteriormente:

Usando iptables SIN los módulos cargados: http://www.busindre.com/archivos/ip_nat_ftp_DISABLE.png
Usando iptables CON los módulos cargados: http://www.busindre.com/archivos/ip_nat_ftp_ENABLE.png

Posted in Linux |

One Response

  1. maiku Says:

    muchas gracias me sirvió mucho para resolver "500 Illegal PORT command."

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.