Porque é que as listagens FTP ficam penduradas atrás de um gateway VPN que faz NAT
O início de sessão e o PWD funcionam, enquanto o LIST e o RETR param quando o NAT só reescreve os cabeçalhos. Veja onde deve ficar o auxiliar FTP e como corrigir o modo passivo.
O início de sessão funciona, o PWD funciona, e depois o LIST fica pendurado até o cliente desistir ou passar para outro modo de dados. Esta separação é a assinatura: a ligação de controlo para a porta 21 está saudável, enquanto a ligação de dados é construída a partir de um endereço ou porto que o outro lado não consegue alcançar. Atrás de um gateway VPN que também faz NAT, o culpado habitual é um comando FTP cuja carga útil indica um endereço de túnel como 10.8.0.6. A tradução dos cabeçalhos nunca toca nesse valor.
O que se segue é de onde vem esse valor, e que caixa tem permissão para o alterar.
O que se parte é a carga útil, não o túnel
O FTP coloca o ponto final dos dados dentro do fluxo de controlo. No modo ativo o cliente envia PORT com o seu próprio endereço e porto, e o servidor liga de volta para esse par. No modo passivo o servidor responde 227 com um par, e o cliente liga a esse par em vez disso.
Ambas as formas transportam o mesmo tipo de afirmação: liga-te a este endereço, neste porto. Um dispositivo que só reescreve cabeçalhos IP e TCP deixa a afirmação intacta, por isso um dos lados continua a tentar alcançar um endereço que só existe do outro lado de um túnel. A ligação de dados pára depois de a ligação de controlo já ter sido declarada saudável.
Três modos, três cargas úteis
A tabela abaixo mostra a que lado se pede que ligue, e o que um NAT que só reescreve cabeçalhos pode fazer quanto a isso.
Leia a última coluna como aquilo que falha primeiro. No modo ativo é o servidor que liga para um endereço privado; no modo passivo é o cliente; com FTPS a carga útil é texto cifrado e a caixa intermédia tem ainda menos com que trabalhar.
| Mode | Value in the control stream | Who dials whom | Header-only NAT leaves |
|---|---|---|---|
| Active (PORT) | client address and port | server dials the client | a server dialing an unreachable tunnel address |
| Passive (227) | server address and port | client dials the server | a client dialing an address it cannot route to |
| FTPS | the same values, inside TLS | as above | ciphertext, so no rewrite happens at all |
Coloque o auxiliar onde acontece a tradução
No Linux a reescrita da carga útil é feita pelo auxiliar nf_conntrack_ftp. Vigia a ligação de controlo, aprende o porto negociado, cria uma expectativa para o fluxo de dados e, numa caixa NAT, reescreve o endereço e o porto dentro da carga útil. Só ajuda no dispositivo que traduz o endereço do cliente. Carregá-lo no cliente, ou num router que apenas reencaminha o fluxo, não altera nada na sessão.
Estes três comandos mostram se o módulo está presente, se está associado e se existe uma expectativa enquanto uma sessão está aberta:
modprobe nf_conntrack_ftp
lsmod | grep nf_conntrack_ftp
conntrack -L expect | grep ftp
Carregar o módulo não é o mesmo que associá-lo. Os kernels desde o 4.7 vêm com net.netfilter.nf_conntrack_helper=0, por isso o auxiliar espera por uma regra explícita, por exemplo iptables -t raw -A PREROUTING -p tcp --dport 21 -j CT --helper ftp. Se a lista de expectativas ficar vazia enquanto se tenta uma transferência, é a associação que deve ser verificada, não o módulo.
Modo passivo: diga ao servidor o que anunciar
O modo passivo é mais fácil de tornar determinístico porque se pode dizer ao servidor o que colocar na resposta 227. No vsftpd isso é pasv_address, juntamente com pasv_min_port e pasv_max_port; o ProFTPD usa MasqueradeAddress e PassivePorts. Defina isso primeiro, porque um endereço anunciado correctamente elimina a necessidade de reescrever o que quer que seja desse lado.
Depois deixe passar exactamente esse intervalo de portos pelo gateway, por exemplo -A FORWARD -i tun0 -p tcp --dport 30000:30100 -j ACCEPT, para que a regra coincida com o que o servidor anuncia.
As duas definições têm de concordar. Um servidor ao qual se diz para anunciar 30000-30100 enquanto o gateway permite 40000-40100 falha da forma menos útil: a conversa de controlo parece saudável e todas as ligações de dados morrem. Compare os números antes de depurar qualquer outra coisa.
Duas assinaturas de falha, e o que o FTPS elimina
Uma pendura no LIST aponta para a primeira ligação de dados da sessão, onde tanto a reescrita do endereço como a expectativa têm de funcionar. Uma pendura no RETR depois de um LIST a funcionar aponta para a transferência em si, ou seja, para o intervalo passivo ou para o MTU do túnel. Essa segunda assinatura não é um problema de carga útil, e as definições do auxiliar não a corrigem.
O FTP sobre TLS elimina a carga útil que o auxiliar lê. Uma caixa intermédia não pode reescrever um valor PORT ou PASV que não consegue decifrar, por isso restam um proxy que termina o TLS, um servidor que anuncia um endereço alcançável dentro de um intervalo limitado, ou um protocolo de transferência diferente.
Uma ordem breve de verificações
Trabalhe do sintoma para fora. Confirme que o LIST falha enquanto o PWD tem sucesso, capture o endereço dentro da carga útil PORT ou 227, e pergunte que dispositivo traduz esse endereço. Associe o auxiliar aí, observe a lista de expectativas durante uma transferência, depois corrija o modo passivo no servidor e reflicta o intervalo na regra do gateway.
Mantenha a falha do caminho de dados separada da falha de transferência massiva, porque levam a definições diferentes.