Colisão portuária efêmera

2

Existe um único aplicativo cliente que faz conexões TCP (HTTP) frequentes ao servidor. A conexão dura a duração de uma solicitação e, em seguida, o servidor fecha a conexão, de forma que o soquete no servidor acabe no estado TIME_WAIT por alguns minutos. À medida que o aplicativo cliente faz solicitações repetidas, o número de conexões TIME_WAIT no servidor aumenta e se instala em soquetes ~ 150 que estão constantemente em TIME_WAIT.

Ocasionalmente, uma nova conexão do cliente escolhe uma porta de origem efêmera usada recentemente que está no estado TIME_WAIT no servidor e a conexão falha. Com 32k de intervalo de portas efêmeras e 150 soquetes em TIME_WAIT, há > 10% de chance de isso acontecer. O cenário exato também é descrito em RFC6056 seção 2.3

Eu não tenho controle sobre o servidor, portanto, reduzir o atraso de TIME_WAIT ou alterar o comportamento não é uma opção. Também é difícil alterar o aplicativo cliente para escolher a porta de origem manualmente, pois estou usando uma biblioteca de terceiros para fazer solicitações HTTP.

O aumento do intervalo de portas efêmeras diminuiria apenas ligeiramente a probabilidade de colisão. Existe uma maneira de alterar a estratégia de seleção de porta efêmera em um cliente (Linux) para evitar tais colisões?

    
por senyacap 15.02.2017 / 10:19

1 resposta

1

Um soquete em TIME-WAIT aceitará de bom grado uma nova conexão de um dispositivo usando a mesma tupla 5 (protocolo, IP de origem, porta de origem, destino, porta de destino), desde que o Número de Sequência Inicial (ISN) do novo a conexão é maior do que o último número de sequência visto na conexão anterior. De acordo com a RFC 1122 :

When a connection is closed actively, it MUST linger in TIME-WAIT state for a time 2xMSL (Maximum Segment Lifetime). However, it MAY accept a new SYN from the remote TCP to reopen the connection directly from TIME-WAIT state, if it:

(1) assigns its initial sequence number for the new connection to be larger than the largest sequence number it used on the previous connection incarnation, and

(2) returns to TIME-WAIT state if the SYN turns out to be an old duplicate.

Você pode testar isso em uma máquina Linux definindo seu intervalo de portas efêmeras para uma única porta echo 32769 32769 > /proc/sys/net/ipv4/ip_local_port_range e, em seguida, fazendo várias solicitações consecutivas para um site com o conjunto de cabeçalhos Connection: Close HTTP wget --no-http-keep-alive www.example.com . Mesmo que a 5 tupla de todas as suas conexões seja a mesma, o servidor aceitará as novas conexões enquanto estiver no TIME-WAIT, porque o ISN de cada nova conexão deve ser maior que o número de sequência visto pela última vez no soquete. No Linux, o ISN de uma nova conexão deve estar aumentando constantemente - está um pouco preso ao clock do sistema.

Se tiver certeza de que TIME-WAIT está sempre terminando no lado do servidor e você não consegue se conectar quando suas portas efêmeras são reutilizadas, o ISN usado pelo seu cliente não deve aumentar para cada nova conexão (talvez está sendo escolhido aleatoriamente ou sempre usa o mesmo valor?). Se você puder garantir que cada nova conexão do seu cliente use um valor ISN mais alto que o anterior, será possível conectar-se sem problemas.

    
por 01.03.2017 / 21:41