O Linux não consegue interpretar o ACK, continua a reenviar o SYN + ACK

5

O seguinte é um despejo wireshark do problema ocorrendo, endereços IP substituídos por 'client' e 'server':

4414.229553  client -> server TCP 62464 > http [SYN] Seq=0 Win=65535 Len=0 MSS=1452 WS=3 TSV=116730231 TSER=0
4414.229633 server -> client  TCP http > 62464 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1460 TSV=2406364374 TSER=116730231 WS=6
4414.263330  client -> server TCP 62464 > http [ACK] Seq=1 Ack=1 Win=524280 Len=0 TSV=116730231 TSER=2406364374
4418.812859 server -> client  TCP http > 62464 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1460 TSV=2406365520 TSER=116730231 WS=6
4418.892176  client -> server TCP [TCP Dup ACK 778#1] 62464 > http [ACK] Seq=1 Ack=1 Win=524280 Len=0 TSV=116730278 TSER=2406365520
4424.812864 server -> client  TCP http > 62464 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1460 TSV=2406367020 TSER=116730278 WS=6
4424.891240  client -> server TCP [TCP Dup ACK 778#2] 62464 > http [ACK] Seq=1 Ack=1 Win=524280 Len=0 TSV=116730337 TSER=2406367020

Assim, a seqüência normal SYN, SYN + ACK, ACK parece ocorrer, exceto que o servidor não parece interpretar o ACK. Em vez disso, ele continua reenviando o SYN + ACK, ao qual o cliente obedientemente responde respondendo com uma duplicata do ACK anterior. Não vejo como isso possa acontecer.

Percebi o problema porque o rastreamento de conexões do iptables considera essas conexões estabelecidas e as mantém na memória por um tempo limite total de 120 horas. Eu tenho algumas regras de firewall para evitar um grande número de conexões simultâneas, os limites que as pessoas estavam atingindo, sem realmente ter que muitas conexões ativas. O comando netstat não mostra essas conexões fantasmas.

Outras informações:

O servidor é um sistema debian lenny padrão com um kernel padrão:

Linux tb 2.6.26-2-686 #1 SMP Wed Aug 19 06:06:52 UTC 2009 i686 GNU/Linux

em execução:

Apache/2.2.9 (Debian) mod_ssl/2.2.9 OpenSSL/0.9.8g

Não tenho todas as informações sobre o cliente (não consigo reproduzir localmente), mas é um Mac que executa o navegador Chrome.

Eu não tenho nenhuma regra de firewall mexendo com pacotes ACK. Basicamente eu apenas filtro pacotes SYN, todos os outros pacotes TCP são permitidos. Portanto, na verdade, não uso o rastreamento de conexão para firewall, além de contar as conexões simultâneas e alguns gráficos dos pacotes Estabelecidos no TCP em comparação com outros tipos de pacotes.

Edit: minhas regras do iptables relacionadas à porta TCP 80:

iptables -P INPUT ACCEPT
iptables -A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 50 -j LOGDROP-CONN
iptables -A INPUT -p tcp --syn -m multiport --dports 80,443 -j ACCEPT
iptables -A INPUT -p tcp --syn -j REJECT --reject-with tcp-reset
iptables -A LOGDROP-CONN -m limit --limit 1/minute --limit-burst 1 -j LOG --log-prefix "ConConn "
iptables -A LOGDROP-CONN -j DROP

Editar 2: outro dump, desta vez usando tcpdump -vv:

16:05:52.999525 IP (tos 0x0, ttl 55, id 46466, offset 0, flags [DF], proto TCP (6), length 64) client.50538 > server.www: S, cksum 0x4429 (correct), 38417001:38417001(0) win 65535 <mss 1452,nop,wscale 3,nop,nop,timestamp 117224762 0,sackOK,eol>
16:05:52.999580 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60) server.www > client.50538: S, cksum 0xa2ab (correct), 3062713115:3062713115(0) ack 38417002 win 5792 <mss 1460,sackOK,timestamp 2418739698 117224762,nop,wscale 6>
16:05:53.321788 IP (tos 0x0, ttl 55, id 24299, offset 0, flags [DF], proto TCP (6), length 52) client.50538 > server.www: ., cksum 0xe813 (correct), 1:1(0) ack 1 win 65535 <nop,nop,timestamp 117224765 2418739698>
16:05:56.252697 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60) server.www > client.50538: S, cksum 0x9f7a (correct), 3062713115:3062713115(0) ack 38417002 win 5792 <mss 1460,sackOK,timestamp 2418740512 117224765,nop,wscale 6>
16:05:56.277250 IP (tos 0x0, ttl 55, id 15533, offset 0, flags [DF], proto TCP (6), length 52) client.50538 > server.www: ., cksum 0xe4c4 (correct), 1:1(0) ack 1 win 65535 <nop,nop,timestamp 117224798 2418740512>
    
por Bart Noordervliet 21.07.2011 / 12:12

2 respostas

2

Eu teria força bruta. Primeiro eu tentaria se funcionasse com o iptables parado. Se isso acontecer, então é algo no iptables.

Depois, adicionaria regras uma por uma e observaria qual delas causa falha de conexão. Então eu jogaria com essa regra até que fizesse o que eu queria, sem interromper totalmente o tráfego.

Se não funcionar com o iptables parado, então ele vai começar a ficar muito estranho.

    
por 21.07.2011 / 17:50
0

OK, não tenho uma resposta completa, mas aprendi muito desde que esse problema apareceu pela primeira vez. Compartilharei minhas ideias aqui.

  • Em primeiro lugar, o problema foi acionado pelo Google Chrome, abrindo um número de soquetes (6 em meus testes) para qualquer site que você abrir com ele. Ele faz isso para iniciar o download dos vários elementos de um site em paralelo. Para sites simples que não têm muitos itens, como o meu, alguns desses soquetes pré-abertos ficam ociosos. Eu li que outros navegadores modernos também fazem isso.
  • O cliente que aciona o problema de rastreamento de conexão provavelmente tem um roteador doméstico quebrado ou algo assim, porque os soquetes inativos tendem a desaparecer sem que nenhum pacote FIN ou RST seja enviado para derrubá-los.
  • A repetição dos pacotes SYN + ACK parece ser um comportamento normal do TCP, eu pude testemunhar isso em vários servidores web de terceiros executando um dump de pacote e então fazendo algo como telnet www.website.com 80 e não enviando nenhum dado . Ainda pode ser uma peculiaridade do Linux, já que os servidores que testei podem muito bem rodar o Linux. Este comportamento também aconteceu sem qualquer iptables-rules carregado, então é realmente relacionado ao kernel.
  • Depois de enviar alguns pacotes SYN + ACK sem resposta, o kernel do Linux derrubará seu lado da conexão. O iptables connection-tracking parece não compartilhar essa lógica, portanto, a conexão permanecerá no estado ESTABLISHED até que ela expire. O tempo limite padrão é de 5 dias (!). Estou planejando reduzir isso para algo mais sensato como algumas horas.
  • Repetir o SYN + ACKs depois de receber o ACK não é completamente um comportamento padrão, pois eu não o vi quando abri uma porta de escuta com nc -l ### e conectado a ele. Portanto, pode ser uma certa opção TCP que o Apache configura em seu soquete de escuta. Ou pode ser algo inteiramente exclusivo do Apache. A maioria dos outros daemons se anunciam imediatamente após a conexão, portanto, eles não são casos de teste válidos para isso. A conexão precisa fazer um handshake de três vias e, em seguida, ficar inativa imediatamente.

Obrigado pelas informações dadas acima, mas elas foram úteis para chegar ao fim.

    
por 22.07.2011 / 22:57