Cuando conectamos a un servidor FTP, tenemos la opción de elegir dos modos de conexión:

  • Modo activo: el cliente establece una conexión al servidor FTP a través del puerto TCP 21, una vez establecida se crea un canal de datos entre el puerto TCP 20 del servidor y un puerto aleatorio superior al 1024 en el cliente.
  • Modo pasivo: el cliente también establece la conexión al servidor FTP a través del puerto TCP 21. Una vez establecida la conexión el servidor abre un puerto aleatorio (> 1024) al que se conectará el cliente.

Me tomo la libertad de adjuntar estos dos esquemas de la Wikipedia, que lo explican de forma más gráfica y amplia:

500px-activo-svg_

500px-pasivo-svg_

Entrando al tema de la entrada, si quisiéramos configurar IPTABLES para permitir conexiones FTP con modo pasivo, no es tan sencillo como hacerlo para el modo activo. El modo activo únicamente necesita tener abiertos los puertos TCP 20 para datos y 21 para establecer la conexión:

# iptables -I INPUT 3 -p tcp --dport 21 -j ACCEPT
# iptables -I INPUT 4 -m state --state RELATED,ESTABLISHED -p tcp --dport 20 -j ACCEPT

Con estas dos reglas permitimos el acceso para cualquier tipo de conexión al puerto 21 y posteriormente las conexiones ya establecidas o relacionadas con destino el puerto 20 (datos FTP). Pero, ¿qué pasa con el modo pasivo? no conocemos cual es el puerto de datos. Está claro que el puerto 21 tcp sí que tendrá que estar abierto como en el modo activo:

# iptables -I INPUT 3 -p tcp --dport 21 -j ACCEPT

Con esta configuración podremos conectar al FTP, pero llegado el momento de transferir datos o incluso listar los ficheros del FTP recibiremos un timeout:

Status: Connected
Status: Retrieving directory listing...
Command: PWD
Response: 257 "/"
Command: TYPE I
Response: 200 Switching to Binary mode.
Command: PASV
Response: 227 Entering Passive Mode (192,168,1,129,54,45).
Command: LIST
Error: Connection timed out
Error: Failed to retrieve directory listing

Los servidores FTP normalmente permiten establecer un rango de puertos aleatorios a ser usados con el modo pasivo. Lo que tenemos que hacer es aceptar ese rango en iptables para conexiones ya establecidas y relacionadas, no es necesario aceptarlo para nuevas conexiones ya que el FTP nunca se va a conectar a ese puerto sin pasar antes por el 21. Si hubieramos configurado el rango 10000-10500 tcp en el servidor FTP añadiríamos esta regla:

# iptables -I INPUT 3 -m state --state ESTABLISHED,RELATED -p tcp --dport 10000:10500 -j ACCEPT

Pero esto no es todo, todavía necesitamos cargar un par de módulos de IPTABLES que sirven para seguir las conexiones FTP y llevar un control sobre ellas. Los módulos son nf_conntrack_ftp e ip_nat_ftp. El primer es necesario siempre y el segundo cuando se trabaja con NAT. En RHEL, CentOS y derivados los módulos se pueden cargar en el fichero /etc/sysconf/iptables-config:

# Load additional iptables modules (nat helpers)
# Default: -none-
# Space separated list of nat helpers (e.g. 'ip_nat_ftp ip_nat_irc'), which
# are loaded after the firewall rules are applied. Options for the helpers are
# stored in /etc/modprobe.conf.
IPTABLES_MODULES="nf_conntrack_ftp ip_nat_ftp"

Una vez cargados, reiniciamos iptables para cargar los módulos y verificamos que han sido cargados con el comando lsmod:

# lsmod | grep ip
nf_conntrack_ipv4 7694 4 nf_nat
nf_defrag_ipv4 1039 1 nf_conntrack_ipv4
iptable_filter 2173 1
ip_tables 9567 1 iptable_filter
ipt_REJECT 1931 2
ip6t_REJECT 3987 2
nf_conntrack_ipv6 7207 2
nf_defrag_ipv6 9873 1 nf_conntrack_ipv6
nf_conntrack 65524 6 nf_nat_ftp,nf_nat,nf_conntrack_ftp,nf_conntrack_ipv4,nf_conntrack_ipv6,xt_state
ip6table_filter 2245 1
ip6_tables 10867 1 ip6table_filter
ipv6 264641 34 ip6t_REJECT,nf_conntrack_ipv6,nf_defrag_ipv6,cnic

Y ya tendremos nuestro firewall configurado para permitir FTP en modo pasivo.