nft config para hacer público un servidor FTP NATed local

nft config para hacer público un servidor FTP NATed local

Todo estará en una red aislada, la seguridad no es un problema.
eth0 está conectado a la red "pública". Dirección asignada por DHCP.
eth1 está conectado a un servidor de "red privada" que proporciona ssh, telnet, "otros" y ftp.
Este servidor tendrá una IP fija (192.168.1.2) en este ejemplo.

La puerta de enlace ejecuta Debian Buster y el kernel de Linux 4.19.94.

nft se usa con NAT.
Esta es mi configuración nft de "puerta de enlace" hasta ahora:

table ip my_nat {
    chain my_prerouting { type nat hook prerouting priority 0;
    tcp dport { 2222 } dnat to :22 # 2222 backdoor for ssh to the gateway
    tcp dport { 1-1023 } dnat to 192.168.1.2
  }
  chain my_postrouting {
    type nat hook postrouting priority 100;
    ip daddr 192.168.1.2  masquerade
  }
}

¿Qué necesito agregar para que FTP funcione?

Respuesta1

TL;DR

# nft add ct helper ip my_nat ftp-incoming '{ type "ftp" protocol tcp; }'
# nft add chain ip my_nat my_helpers '{ type filter hook prerouting priority 10; }'
# nft add rule ip my_nat my_helpers iif eth0 ip daddr 192.168.1.2 tcp dport 21 ct helper set ftp-incoming
# modprobe nf_nat_ftp

con más detalles a continuación...

Módulos auxiliares de protocolo para protocolos problemáticos

FTP es un protocolo antiguo y no es muy compatible con firewalls: los comandos en el canal de comando FTP (21/TCP) negocian un puerto efímero para usarlo en el siguiente comando de transferencia. Debido a esto, un firewall con estado tiene que espiar esos comandos y respuestas para permitir previamente temporalmente el puerto adecuado que está a punto de usarse.

En Linux, esto lo proporcionan módulos auxiliares específicos del protocolo que son complementos paraconectar, el subsistema Netfilter que rastrea conexiones para NAT y firewall con estado. Con FTP, cuando se ve una negociación de puerto (principalmente PORT, EPRT, PASV o EPSV) para la siguiente transferencia en el puerto de comando FTP, el asistente agrega una entrada de corta duración en un archivo especial.conectarmesa (laexpectativa de seguimientotable) que esperará la siguiente conexión de datos relacionada y esperada.

Mi respuesta utiliza el manejo "seguro" moderno como se describe eneste blog sobreiptablespara generalidades y en elnftableswikiyman nftpara el manejo ennftablesque difiere deiptables.

Uso seguro de reglas auxiliares y nftables

El kernel de Linux 4.7+ (por lo que incluye 4.19) utiliza un enfoque seguro de forma predeterminada: tener el módulo auxiliar (aquí FTP) cargado ya no hará que espíe todos los paquetes que tengan un puerto TCP de origen o destino 21, hasta que se especifique lo contrario.nftables(oiptables) le indican en qué caso (restringido) debe espiar. Esto evita el uso innecesario de la CPU y permite cambiar en cualquier momento el puerto FTP para espiar simplemente cambiando algunas reglas (o conjuntos).

La primera parte es declarar los flujos que pueden desencadenar el espionaje. Se maneja de manera diferente ennftablesque eniptables. Aquí se declara usando un ct helperobjeto con estado, y los filtros para activarlo deben realizarse despuésconectar(mientrasiptablesrequiere acciones realizadas antes).man nftdice:

A diferencia de iptables, la asignación de ayuda debe realizarse después de que se haya completado la búsqueda de conntrack, por ejemplo con la prioridad de enlace predeterminada 0.

nft add ct helper ip my_nat ftp-incoming '{ type "ftp" protocol tcp; }'

nft add chain ip my_nat my_helpers '{ type filter hook prerouting priority 10; }'
nft add rule ip my_nat my_helpers iif eth0 ip daddr 192.168.1.2 tcp dport 21 ct helper set ftp-incoming

Elegí la misma tabla, pero podría haberse creado en otra tabla, siempre que la declaración del objeto con estado y la regla que hace referencia a ella estén en la misma tabla.

Por supuesto, se pueden elegir normas menos restrictivas. Reemplazar la última regla por la siguiente regla tendría el mismo efecto que el modo heredado:

nft add rule ip my_nat my_helpers tcp dport 21 ct helper set ftp-incoming

Solo como referencia, el modo heredado, que ya no debería usarse, no requiere las reglas anteriores, solo esta opción (y la carga manual del módulo del kernel correspondiente):

sysctl -w net.netfilter.nf_conntrack_helper=1

Asegurándose nf_nat_ftpde que esté cargado

El módulo del kernel nf_conntrack_ftpse carga automáticamente con la dependencia creada por ct helper ... type "ftp". Ese no es el caso de nf_nat_ftp, pero también es necesario habilitar la manipulación de paquetes en el puerto de comando cuando se realiza NAT en los puertos de flujo de datos.

Por ejemplo, para nf_nat_ftpextraer el módulo cada vez que nf_conntrack_ftpse carga, /etc/modprobe.d/local-nat-ftp.confse podría agregar el archivo con este contenido:

install nf_conntrack_ftp /sbin/modprobe --ignore-install nf_conntrack_ftp; /sbin/modprobe --ignore-install nf_nat_ftp

o en su lugar, simplemente agregue por ejemplo /etc/modules-load.d/local-nat-ftp.confcon:

nf_nat_ftp

De todos modos, ahora mismo se debe ejecutar este comando para garantizar que esté cargado:

modprobe nf_nat_ftp

Acerca del cortafuegos

Aquí hay una nota adicional para el firewall. También puede haber reglas de firewall con algunas restricciones en lugar de permitir cualquier flujo nuevo etiquetado comorelacionadoporconectar.

Por ejemplo, aunque el módulo auxiliar FTP maneja tanto el modo pasivo como el activo, si por alguna razón uno quiere permitir sólo el modo pasivo (con conexión de datos del cliente al servidor) y no ftp "activo" (conexión de datos desde el puerto de origen del servidor 20 al cliente) se podrían usar, por ejemplo, estas reglas en la parte del firewall del conjunto de reglas, en lugar de lo habitual ct state established,related accept:

ct state established accept
ct state related ct helper "ftp" iif eth0 oif eth1 tcp sport 1024-65535 accept
ct state related ct helper "ftp" drop
ct state related accept 

Otro tipo derelacionadolos flujos no relacionados con FTP se mantienen aceptados (o podrían dividirse aún más por separado)


Ejemplo de manipulación por parte del ayudante.

Aquí (en un entorno simulado) hay dosconectarlistas de eventos medidos en elexpectativamesa y elconectartabla con las reglas del OP + las reglas adicionales anteriores con un cliente de Internet 203.0.113.101 haciendo FTP en modo pasivo con la dirección IP pública del enrutador 192.0.2.2 y usando un comando LIST después de haber iniciado sesión:

# conntrack -E expect
    [NEW] 300 proto=6 src=203.0.113.101 dst=192.0.2.2 sport=0 dport=37157 mask-src=0.0.0.0 mask-dst=0.0.0.0 sport=0 dport=65535 master-src=203.0.113.101 master-dst=192.0.2.2 sport=50774 dport=21 class=0 helper=ftp
[DESTROY] 300 proto=6 src=203.0.113.101 dst=192.0.2.2 sport=0 dport=37157 mask-src=0.0.0.0 mask-dst=0.0.0.0 sport=0 dport=65535 master-src=203.0.113.101 master-dst=192.0.2.2 sport=50774 dport=21 class=0 helper=ftp

simultáneamente:

# conntrack -E
    [NEW] tcp      6 120 SYN_SENT src=203.0.113.101 dst=192.0.2.2 sport=50774 dport=21 [UNREPLIED] src=192.168.1.2 dst=192.168.1.1 sport=21 dport=50774 helper=ftp
 [UPDATE] tcp      6 60 SYN_RECV src=203.0.113.101 dst=192.0.2.2 sport=50774 dport=21 src=192.168.1.2 dst=192.168.1.1 sport=21 dport=50774 helper=ftp
 [UPDATE] tcp      6 432000 ESTABLISHED src=203.0.113.101 dst=192.0.2.2 sport=50774 dport=21 src=192.168.1.2 dst=192.168.1.1 sport=21 dport=50774 [ASSURED] helper=ftp
    [NEW] tcp      6 120 SYN_SENT src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 [UNREPLIED] src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835
 [UPDATE] tcp      6 60 SYN_RECV src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835
 [UPDATE] tcp      6 432000 ESTABLISHED src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835 [ASSURED]
 [UPDATE] tcp      6 120 FIN_WAIT src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835 [ASSURED]
 [UPDATE] tcp      6 30 LAST_ACK src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835 [ASSURED]
 [UPDATE] tcp      6 120 TIME_WAIT src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835 [ASSURED]

El inicio de la expectativa proto=6 src=203.0.113.101 dst=192.0.2.2 sport=0 dport=37157indica que se asociará la siguiente conexión TCP de 203.0.113.101:* a 192.0.2.2:37157 (estadorelacionado) con la conexión FTP. No es visible directamente, pero dado que el módulo auxiliar NAT FTP también está cargado, los datos reales enviados por el servidor en respuesta al comando PASV/EPSV fueron interceptados y traducidos para que el cliente se conecte a 192.0.2.2 en lugar de 192.168.1.2 que habría sido Por supuesto, falló en el cliente.

A pesar del segundo flujo (segundoNUEVOlínea) que no tiene ninguna regla explícita enmi_preenrutamiento, se realizó DNAT con éxito en el servidor detrás del enrutador.


Notas

  • Si el puerto de control FTP está cifrado ( AUTH TLS...), entonces el módulo auxiliar ya no puede espiar el puerto negociado y esto no puede funcionar. Hay que recurrir a la configuración de un rango reservado de puertos tanto en la configuración del servidor FTP como en el firewall/enrutador NAT, y configurar el servidor para que envíe la dirección IP (pública) correcta al negociar en lugar de la suya propia. Y el modo FTP activo no se puede utilizar si el servidor no tiene ruta a Internet (como parece ser el caso aquí).

  • quisquilloso: la prioridad de enrutamiento previo de 10 garantiza que incluso para kernels < 4.18, NAT ya se haya implementado para nuevos flujos (OP eligió la prioridad de enrutamiento previo del gancho 0 en lugar de la habitual -100, ya que esto rara vez importa en nftables), por lo que daddr 192.168.1.2es posible el uso de. Si la prioridad fuera 0 (o inferior a 0), tal vez sea posible (no verificado) que la regla vea el primer paquete aún sin NAT con una dirección IP de destino pública, pero capture los siguientes paquetes del mismo flujo, ya que son manejados. directamente porconectaren prioridad -200. Mejor manténgase seguro y use 10. En realidad, esto no es relevante desde el kernel 4.18 (vercomprometersereferencia enesteparche pendiente) donde la prioridad NAT solo es relevante para comparar entre múltiples cadenas nat (y permite mezclar NAT en el legado de iptables junto con nftables).

Respuesta2

Después de algunas pruebas y errores, se me ocurrió el siguiente nftables.conf. Esto funciona según lo previsto y admite NAT en ambas direcciones, además de exportar todos los puertos menos uno de mi servidor a la red "pública". El puerto 2222 todavía se usa como "puerta trasera" para la puerta de enlace, para usarlo si alguna vez necesito acceder a él nuevamente :-)

table ip my_nat {
        ct helper ftp-incoming {
                type "ftp" protocol tcp
                l3proto ip
        }

        chain my_prerouting {
                type nat hook prerouting priority 0; policy accept;
                iifname "eth0" tcp dport { 2222 } dnat to :ssh
                iifname "eth0" tcp dport { 1-2221, 2223-65535 } dnat to 192.168.0.2
        }

        chain my_postrouting {
                type nat hook postrouting priority 100; policy accept;
                ip daddr 192.168.0.2 masquerade
                oifname "eth0" masquerade
        }

        chain my_helpers {
                type filter hook prerouting priority 10; policy accept;
                iif "eth0" ip daddr 192.168.0.2 tcp dport ftp ct helper set "ftp-incoming"
        }

}

información relacionada