Diagnosticando "Connection timed out"

Diagnosticando "Connection timed out"

O que significa "Connection timed out"?

Conclusão: Você enviou uma requisição de conexão e nada retornou. O destino -- ou um dispositivo no caminho -- está descartando pacotes silenciosamente (DROP), ou o destino está desligado. O kernel retenta, depois desiste. A característica definidora é a espera de vários segundos a dezenas de segundos antes da falha.

Connection timed out aparece quando você envia um SYN ao destino, nenhum SYN+ACK retorna, e o kernel esgota suas retransmissões e desiste. No nível de chamada de sistema, connect() retorna ETIMEDOUT, que as aplicações apresentam como "Connection timed out".

$ ssh user@192.0.2.10
ssh: connect to host 192.0.2.10 port 22: Connection timed out
$ curl http://192.0.2.10/
curl: (28) Failed to connect to 192.0.2.10 port 80 after 129000 ms: Connection timed out

O que o diferencia de refused (rejeitado instantaneamente) e No route to host (retornado inacessível instantaneamente) é que ele falha após um longo silêncio. Esse silêncio é a assinatura de "alguém está descartando pacotes sem dizer nada" -- quase sempre um firewall DROP ou um host ausente.

Pré-requisitos

  • SO: Ubuntu / uma distribuição Linux típica (usa ss / traceroute / tcpdump)
  • Alvo: um host que você quer alcançar por IP e porta
  • Algumas verificações precisam de sudo (tcpdump / nft, etc.)

Qual a diferença de refused e No route to host?

Conclusão: Refused significa "chegou mas a porta rejeitou (RST instantâneo)", No route to host significa "não há caminho (ICMP instantâneo)", e timed out significa "nenhuma resposta (longa espera)". Mesma conexão falhada -- o tempo antes da resposta indica qual camada está com problema.

Erros de conexão se dividem em três famílias pela forma como a resposta retorna. Determine primeiro qual você tem.

Erro O que retorna Camada da causa
Connection refused TCP RST (instantâneo) Serviço / porta (L4, app)
No route to host ICMP unreachable (instantâneo) Rota / ARP / REJECT (L2-L3)
Connection timed out Sem resposta (longa espera) DROP / caminho silencioso (L3-L4)
$ time curl -sS http://192.0.2.10/
curl: (28) Failed to connect to 192.0.2.10 port 80 after 129000 ms: Connection timed out

real    2m9.012s

Se leva vários segundos ou mais para falhar, você tem a família timed-out: alguém está descartando pacotes silenciosamente. Se falhou instantaneamente, o problema é outro. Para um serviço parado ou porta fechada veja Diagnosticando Connection refused; para ausência total de caminho veja Diagnosticando No route to host. Este artigo cobre Connection timed out.

Refused é "o host está vivo mas a porta me recusou"; timed out é "ninguém responde". O primeiro dá uma resposta clara (RST); o segundo é silêncio. Silêncio é a marca do DROP -- um firewall descartando com -j DROP, ou um host que não está lá.

Por que "Connection timed out" acontece?

Conclusão: A causa se reduz a quatro coisas -- (1) firewall DROP (mais comum), (2) security group de cloud não aberto, (3) host inativo ou sem listener, ou (4) blackhole no caminho. Trabalhe da camada mais próxima do seu host para fora.

Os caminhos que produzem ETIMEDOUT, organizados por causa:

Causa O que está acontecendo Por onde começar
Firewall DROP O servidor / um dispositivo no caminho descarta SYN silenciosamente nft list ruleset
Security group não aberto Um SG / NACL de cloud não permite a porta Console da cloud
Host inativo / sem listener O servidor está desligado / o serviço não iniciou ss -ltn no servidor
Blackhole no caminho Erro de roteamento / VPN ou buraco de rota consome pacotes traceroute / mtr

Faça a triagem da camada mais próxima do seu host para fora. Primeiro confirme que realmente é timed out pela espera, depois veja até onde no caminho os pacotes chegam, e finalmente inspecione o lado do servidor e seu firewall.

DROP e REJECT são opostos. DROP descarta o pacote silenciosamente, então o cliente não vê resposta e dá timeout. REJECT retorna um ICMP ou RST, então o cliente vê No route to host ou refused. Resumindo: "um longo silêncio = DROP", "um erro instantâneo = REJECT" -- o sintoma revela como o firewall está descartando.

O que verificar primeiro? (Medir a espera)

Conclusão: Limite a espera com curl --connect-timeout ou nc -w e teste apenas a conexão. Se esperar o timeout completo antes de falhar, a ausência de resposta (timed out) está confirmada. Não é necessário esperar o tempo padrão longo.

Primeiro defina um timeout curto e explícito e teste apenas a fase de conexão. Esperar o padrão (cerca de 2 minutos para curl) é desperdicio.

# Limitar o estabelecimento da conexao a 5 segundos
$ curl -sS --connect-timeout 5 http://192.0.2.10/
curl: (28) Failed to connect to 192.0.2.10 port 80 after 5001 ms: Connection timed out

nc (netcat) oferece uma verificação de alcançabilidade ainda mais direta.

$ nc -vz -w3 192.0.2.10 80
nc: connect to 192.0.2.10 port 80 (tcp) failed: Connection timed out

Se falha apenas após a espera completa (3 segundos acima), o destino não está retornando nada ao seu SYN. Se diz refused instantaneamente, a porta está fechada mas o host está respondendo -- isso não é timed out.

--connect-timeout limita o estabelecimento da conexão, enquanto -m (--max-time) limita a transferência inteira. Para triagem você quer apenas a fase de conexão, então use --connect-timeout. O timeout -w do nc também limita a espera de conexão.

Onde no caminho ele para? (traceroute / mtr)

Conclusão: Use traceroute / mtr para ver quantos saltos seus pacotes alcançam em direção ao destino. O ponto após o qual tudo vira * * * é o limite onde os pacotes desaparecem (são DROPados).

Visualize onde no caminho os pacotes desaparecem.

$ traceroute -n 192.0.2.10
 1  10.0.0.1    0.4 ms   0.3 ms   0.3 ms
 2  100.64.0.1  1.2 ms   1.1 ms   1.0 ms
 3  * * *
 4  * * *

Se os saltos até 2 respondem e do 3 em diante são todos * * *, os pacotes estão sendo descartados silenciosamente naquele limite. Além dele há um blackhole, e um firewall ou buraco de roteamento é o suspeito.

Mas traceroute usa ICMP/UDP, então em um ambiente onde TCP passa mas apenas ICMP é bloqueado, pode parecer incorretamente que "para no caminho". Para sondar com a porta que você realmente quer, use o modo TCP.

# Trace com TCP SYN para a porta de destino 80
$ sudo traceroute -T -p 80 -n 192.0.2.10

Para uma visão continua, mtr é prático.

$ mtr -n -T -P 80 192.0.2.10

Se apenas o último salto é * * * enquanto tudo antes responde, o firewall do destino pode estar descartando ICMP mas passando TCP. Não conclua DROP apenas por "traceroute parou" -- sempre confirme com o protocolo e porta em que você quer conectar (-T -p).

Como confirmar que SYN fica sem resposta? (tcpdump)

Conclusão: Observar pacotes reais com tcpdump mostra diretamente que SYN é enviado mas nenhum SYN+ACK retorna. "Enviado mas sem resposta" no cliente e "SYN nunca chegou" no servidor delimitam onde o DROP está.

Quando você quer prova, observe os pacotes diretamente. Capture no cliente enquanto tenta a conexão.

# Execute em outro terminal, depois tente a conexao
$ sudo tcpdump -ni any host 192.0.2.10 and port 80
10:00:00.100 IP 10.0.0.42.51000 > 192.0.2.10.80: Flags [S], seq 1, ...
10:00:01.100 IP 10.0.0.42.51000 > 192.0.2.10.80: Flags [S], seq 1, ...
10:00:03.100 IP 10.0.0.42.51000 > 192.0.2.10.80: Flags [S], seq 1, ...

Apenas Flags [S] (SYN) é retransmitido em intervalos crescentes (1s, 2s, 4s...), e nenhum Flags [S.] (SYN+ACK) retorna. Isso é o timed out em si: o pacote não alcança o destino, ou chega e é ignorado.

Se você consegue acessar o servidor, capturar no servidor também, ao mesmo tempo, torna decisivo.

# Execute no servidor
$ sudo tcpdump -ni any tcp port 80
  • SYN não chega no servidor -> DROP no caminho (um roteador / SG de cloud)
  • SYN chega mas não é respondido -> DROP do firewall local do servidor, ou nenhum listener

Ver os intervalos de retransmissão do SYN (o backoff exponencial de aproximadamente 1, 2, 4, 8 segundos) é em si prova sólida de "sem resposta". A contagem de retentativas é definida por net.ipv4.tcp_syn_retries (padrão 6), e governa a espera total do cliente.

Como identificar um firewall DROP?

Conclusão: Se dá timeout mas os pacotes chegam ao destino, uma regra -j DROP é o principal suspeito. No servidor, verifique nft list ruleset / iptables -L para ver se a porta está permitida. Na cloud, o security group na frente do firewall do SO é a causa com muito mais frequência.

Inspecione as regras de filtragem no servidor.

# Inspecionar regras nftables
$ sudo nft list ruleset | grep -i -E 'drop|policy'

# Em sistemas usando iptables
$ sudo iptables -L -n -v --line-numbers
Chain INPUT (policy DROP)
pkts bytes target  prot  ...  destination
 ...  ...  ACCEPT  tcp   ...  tcp dpt:22

Com policy DROP e apenas porta 22 permitida, um SYN para porta 80 é silenciosamente descartado e o cliente dá timeout. Se você usa ufw, verifique o que está permitido.

$ sudo ufw status verbose

Para recuperar quando o ufw bloqueia até o SSH, veja Troubleshooting ufw e SSH.

Na cloud (AWS / GCP / Azure, etc.), o security group ou network ACL na frente do firewall do SO é de longe o culpado mais frequente. Se nft list ruleset está vazio mas ainda dá timeout, primeiro verifique no console que o SG de cloud permite a porta (e a faixa de IP de origem). Um security group tem como padrão "negar todo inbound" (efetivamente DROP).

O servidor está sequer escutando?

Conclusão: Mesmo com o firewall aberto, nada conecta se o serviço não está rodando. No servidor, verifique ss -ltn para ver se a porta está em LISTEN e se está vinculada apenas a 127.0.0.1.

Se você consegue acessar o servidor, verifique diretamente se a porta está escutando.

$ ss -ltn
State   Recv-Q  Send-Q  Local Address:Port   Peer Address:Port
LISTEN  0       128         127.0.0.1:80          0.0.0.0:*
LISTEN  0       128           0.0.0.0:22          0.0.0.0:*

Se a porta 80 está escutando em 127.0.0.1:80, ela aceita apenas conexões locais e nada chega de fora (abrir o firewall não ajudará). Corrija a configuração de bind do serviço para escutar em 0.0.0.0:80 (todas as interfaces) ou o IP relevante.

Se a porta não está na lista, o serviço não está rodando. Verifique seu estado.

$ systemctl status nginx

Um bind 127.0.0.1 normalmente deveria produzir um refused instantâneo, não um timeout -- mas se um firewall na frente faz DROP, o sintoma é mascarado como timed out. Quando "abri o firewall mas ainda não conecta", sempre suspeite do endereço de bind.

Checklist quando ainda falha

Conclusão: Timed out significa "sem resposta". Trabalhando do seu host para fora -- tempo de espera -> caminho -> resposta SYN -> firewall -> listener -- a causa se reduz a DROP, security group, serviço inativo ou blackhole no caminho.

  • [ ] Levou vários segundos ou mais para falhar (um erro instantâneo é refused / No route to host)?
  • [ ] Você limitou a fase de conexão com curl --connect-timeout / nc -w?
  • [ ] Você tracou com traceroute -T -p <port> na porta que realmente quer?
  • [ ] Você encontrou qual salto vira * * * (o limite do DROP)?
  • [ ] O tcpdump mostrou SYN retransmitindo sem SYN+ACK?
  • [ ] O SYN chega no servidor também (não = caminho / SG, sim = FW local / sem listener)?
  • [ ] Existe um DROP para a porta em nft list ruleset / iptables -L?
  • [ ] O security group / NACL da cloud permite a porta e a origem?
  • [ ] A porta está em LISTEN em 0.0.0.0 (publicamente) em ss -ltn?

Próximas leituras