configuração nft para disponibilizar publicamente um servidor FTP NATed local

configuração nft para disponibilizar publicamente um servidor FTP NATed local

Tudo estará em uma rede isolada, a segurança não é problema.
eth0 está conectado à rede "pública". Endereço atribuído pelo DHCP.
eth1 está conectado a um servidor de "rede privada" que fornece ssh, telnet, "outros" e ftp.
Este servidor terá um IP fixo (192.168.1.2) neste exemplo.

O gateway está executando o debian buster e o kernel Linux 4.19.94

nft é usado com NAT.
Esta é a configuração do meu "gateway" nft até agora:

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
  }
}

O que preciso adicionar para fazer o FTP funcionar

Responder1

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

com mais detalhes abaixo...

Módulos auxiliares de protocolo para protocolos problemáticos

FTP é um protocolo antigo e não é muito compatível com firewall: comandos no canal de comando FTP (21/TCP) negociam uma porta efêmera para usar no próximo comando de transferência. Por causa disso, um firewall com estado precisa espionar esses comandos e respostas para pré-permitir temporariamente a porta adequada que está prestes a ser usada.

No Linux, isso é fornecido por módulos auxiliares específicos do protocolo, que são plug-ins paraconexão, o subsistema Netfilter que rastreia conexões para NAT e firewall com estado. Com o FTP, quando uma negociação de porta (principalmente PORT, EPRT, PASV ou EPSV) para a próxima transferência for vista na porta de comando do FTP, o auxiliar adiciona uma entrada de curta duração em um arquivo especial.conexãomesa (oexpectativa de conexãotabela) que aguardará a próxima conexão de dados relacionada e esperada.

Minha resposta usa o tratamento "seguro" moderno, conforme descrito emeste blog sobretabelas de ippara generalidades e nonftáveiswikieman nftpara o manuseio emnftáveisque difere detabelas de ip.

Uso seguro de regras auxiliares e nftables

O kernel Linux 4.7+ (incluindo 4.19) está usando uma abordagem segura por padrão: ter o módulo auxiliar (aqui FTP) carregado não fará mais com que ele espione todos os pacotes que tenham uma porta TCP de origem ou destino 21, até que seja específiconftáveis(outabelas de ip) declarações informam em que caso (restrito) ele deve bisbilhotar. Isso evita o uso desnecessário da CPU e permite alterar a qualquer momento a(s) porta(s) FTP para espionar apenas alterando algumas regras (ou conjuntos).

A primeira parte é declarar os fluxos que podem desencadear a espionagem. É tratado de forma diferente emnftáveisdo que emtabelas de ip. Aqui ele é declarado usando um ct helperobjeto stateful, e os filtros para ativá-lo devem ser feitos apósconexão(enquantotabelas de iprequer ações feitas antes).man nftdiz:

Ao contrário do iptables, a atribuição do auxiliar precisa ser executada após a conclusão da pesquisa do conntrack, por exemplo, com a prioridade de gancho 0 padrão.

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

Escolhi a mesma tabela, mas esta poderia ter sido criada em outra tabela, desde que a declaração do objeto stateful e a regra que a referencia estejam na mesma tabela.

É claro que podemos escolher regras menos restritivas. Substituir a última regra pela seguinte regra teria o mesmo efeito que o modo legado:

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

Apenas para referência, o modo legado, que não deve mais ser usado, não requer as regras acima, mas apenas esta alternância (e o carregamento manual do módulo relevante do kernel):

sysctl -w net.netfilter.nf_conntrack_helper=1

Garantir nf_nat_ftpque esteja carregado

O módulo do kernel nf_conntrack_ftpé carregado automaticamente com a dependência criada pelo ct helper ... type "ftp". Esse não é o caso nf_nat_ftp, mas é necessário também ativar a manipulação de pacotes na porta de comando quando o NAT é feito nas portas de fluxo de dados.

Por exemplo, para que o módulo seja nf_nat_ftpextraído sempre que nf_conntrack_ftpfor carregado, o arquivo /etc/modprobe.d/local-nat-ftp.confpode ser adicionado com este conteúdo:

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

ou em vez disso, simplesmente adicione, por exemplo, /etc/modules-load.d/local-nat-ftp.confcom:

nf_nat_ftp

De qualquer forma, agora este comando deve ser executado para garantir que esteja carregado:

modprobe nf_nat_ftp

Sobre firewall

Aqui está uma observação adicional sobre firewall. Também pode haver regras de firewall com algumas restrições em vez de permitir qualquer novo fluxo marcado comorelacionadoporconexão.

Por exemplo, embora o módulo auxiliar FTP lide com os modos passivo e ativo, se por algum motivo alguém quiser permitir apenas o modo passivo (com conexão de dados do cliente para o servidor) e não o FTP "ativo" (conexão de dados da porta de origem do servidor 20 para cliente) pode-se usar, por exemplo, estas regras na parte do firewall do conjunto de regras, em vez do 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 

Outro tipo derelacionadofluxos não relacionados ao FTP são mantidos aceitos (ou podem ser divididos separadamente)


Exemplo de manuseio pelo ajudante

Aqui (em um ambiente simulado) estão doisconexãolistas de eventos medidos noexpectativamesa e oconexãotabela com as regras do OP + as regras adicionais acima com um cliente Internet 203.0.113.101 fazendo FTP em modo passivo com o endereço IP público do roteador 192.0.2.2 e usando um comando LIST após ter logado:

# 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

simultaneamente:

# 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]

O início da expectativa proto=6 src=203.0.113.101 dst=192.0.2.2 sport=0 dport=37157informa que a próxima conexão TCP de 203.0.113.101:* a 192.0.2.2:37157 estará associada (estadorelacionado) com a conexão FTP. Não visível diretamente, mas como o módulo auxiliar NAT FTP também está carregado, os dados reais enviados pelo servidor em resposta ao comando PASV/EPSV foram interceptados e traduzidos para que o cliente se conectasse a 192.0.2.2 em vez de 192.168.1.2, o que teria é claro que falhou no cliente.

Apesar do segundo fluxo (segundoNOVOlinha) não tendo nenhuma regra explícita emmeu_pré-routing, ele foi DNATado com sucesso no servidor por trás do roteador.


Notas

  • se a porta de controle FTP estiver criptografada ( AUTH TLS...), então o módulo auxiliar não poderá mais bisbilhotar a porta negociada e isso não poderá funcionar. É necessário recorrer à configuração de um intervalo reservado de portas tanto na configuração do servidor FTP quanto no firewall/roteador NAT, e configurar o servidor para que ele envie o endereço IP (público) correto ao negociar, em vez do seu próprio. E o modo FTP ativo não pode ser usado se o servidor não tiver rota para a Internet (como parece ser o caso aqui).

  • nitpicking: a prioridade de pré-roteamento de 10 garante que mesmo para kernels <4.18, o NAT já aconteceu para novos fluxos (o OP escolheu a prioridade de pré-roteamento de gancho 0 em vez do usual -100, pois isso raramente importa em nftables), então o uso de daddr 192.168.1.2é possível. Se a prioridade fosse 0 (ou inferior a 0), talvez seja possível (não verificado) que a regra veria o primeiro pacote ainda sem NAT com um endereço de destino IP público, mas capturaria os seguintes pacotes do mesmo fluxo, uma vez que eles são manipulados diretamente porconexãona prioridade -200. É melhor ficar seguro e usar o 10. Na verdade, isso não é relevante desde o kernel 4.18 (vejacomprometer-sereferência emessepatch pendente) onde a prioridade NAT é relevante apenas para comparação entre múltiplas cadeias nat (e permite misturar NAT em iptables legados junto com nftables).

Responder2

Depois de algumas tentativas e erros, descobri o seguinte nftables.conf. Ele funciona conforme o esperado e oferece suporte a NAT em ambas as direções, além de exportar todas as portas do meu servidor, exceto uma, para a rede "pública". A porta 2222 ainda é usada como "backdoor" para o gateway, para ser usada caso eu precise acessá-la novamente :-)

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"
        }

}

informação relacionada