Home Comunidade Eventos YouTube Networks Desafios // produtos Academy News CTI | CVE Contato

02 - Servidor Descobre Porta do Cliente na Requisição

video explicativo
Video explicativoEspaco reservado para o video desta anotação — adicione video: https://youtu.be/... no frontmatter da nota.

Servidor Descobre Porta do Cliente na Requisição

1. Definição e Mecanismo Fundamental

Quando um cliente (por exemplo, um navegador) abre uma conexão TCP para um servidor web, ele escolhe aleatoriamente uma porta de origem efêmera (porta alta, normalmente entre 1024 e 65535) e usa como porta de destino a porta bem conhecida do serviço (80 para HTTP, 443 para HTTPS). O servidor, ao receber o segmento TCP, descobre a porta do cliente simplesmente lendo o campo Source Port do cabeçalho TCP. Não há negociação prévia nem protocolo auxiliar — a informação está literalmente em cada pacote recebido.

Estrutura do Cabeçalho TCP

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |  <- bytes 0-3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Sequence Number                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Acknowledgment Number                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Data |           |U|A|P|R|S|F|                               |
| Offset| Reserved  |R|C|S|S|Y|I|            Window             |
|       |           |G|K|H|T|N|N|                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Checksum            |         Urgent Pointer        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Os 2 primeiros bytes do cabeçalho TCP são sempre a porta de origem. O servidor web faz recvfrom() e o kernel entrega, junto com o payload, a struct sockaddr_in preenchida com o IP e a porta do cliente. É exatamente assim que o Apache, o NGINX e qualquer servidor descobrem para quem responder.

2. O Conceito de Socket (Quádrupla)

A unidade de identificação de uma conexão TCP é o socket pair (quádrupla):

{ IP_origem, Porta_origem, IP_destino, Porta_destino }

Um servidor que escuta em :80 pode atender milhares de clientes simultâneos porque o kernel mantém uma tabela hash com todas as conexões ativas, indexada por essa quádrupla. Quando um segmento chega, o kernel extrai os 4 campos do cabeçalho IP+TCP e faz lookup nessa tabela para entregar o payload ao processo correto. Por isso a porta do cliente é essencial: sem ela, o kernel não conseguiria diferenciar duas conexões vindas do mesmo IP.

Exemplo Prático

# Cliente 1 (porta 51000) e Cliente 2 (porta 51001), mesmo IP 192.168.1.10
# servidores web os veem como sockets distintos:
192.168.1.10:51000  <->  203.0.113.10:80   (conexão 1)
192.168.1.10:51001  <->  203.0.113.10:80   (conexão 2)

3. Faixas de Portas Efêmeras por Sistema Operacional

A escolha da porta de origem é feita pelo kernel do cliente, respeitando faixas configuráveis (RFC 6056 recomenda aleatorização para evitar previsibilidade):

Sistema Faixa Padrão Configuração
Linux 32768–60999 cat /proc/sys/net/ipv4/ip_local_port_range
Windows 10/11 49152–65535 netsh int ipv4 show dynamicport tcp
macOS 49152–65535 sysctl net.inet.ip.portrange
FreeBSD 10000–65535 sysctl net.inet.ip.portrange

A IANA divide oficialmente as portas em três faixas (RFC 6335):

  • 0–1023: well-known (sistemas Unix exigem root para bind).
  • 1024–49151: registered (registradas na IANA para aplicações específicas).
  • 49152–65535: dynamic/ephemeral (uso livre pelo kernel).

4. Como o Servidor Mantém a Sessão

O HTTP até a versão 1.0 tratava cada requisição como uma conexão nova: o servidor abria, respondia e fechava. A porta de origem mudava a cada conexão, o que era caro (overhead de handshake TCP). O HTTP/1.1 (RFC 7230) introduziu keep-alive por padrão, permitindo múltiplas requisições reusando a mesma porta de origem, reduzindo latência.

Identificação de Sessão HTTP

Como o HTTP é stateless, aplicações web precisam associar múltiplas requisições a um mesmo usuário. As estratégias comuns são:

  1. IP + Porta de origem: era comum nos anos 1990, mas quebra com NAT (vários usuários compartilham o IP público) e proxies.
  2. Cookies de sessão: o servidor envia Set-Cookie: sessionid=abc123 na primeira resposta e o cliente reenvia Cookie: sessionid=abc123 nas subsequentes. É o padrão atual.
  3. Tokens JWT/URL rewriting: alternativas stateless onde o estado está embutido no token assinado.

A porta de origem nunca deve ser usada como identificador de sessão persistente, porque ela muda a cada nova conexão TCP.

5. Problemas com NAT e Proxies

NAT de Origem (SNAT)

Um roteador doméstico faz SNAT: reescreve o IP de origem do pacote do cliente (192.168.1.10) para o IP público (200.150.0.5) e também reescreve a porta de origem se houver colisão. O servidor web enxerga apenas o IP público e uma porta traduzida. Isso quebra a associação IP+porta = cliente único.

Proxies Reversos e L7

Proxies como NGINX, HAProxy e Cloudfront recebem a requisição do cliente, abrem uma conexão própria para o backend e repassam. Para o backend, a porta de origem é a do proxy, não a do cliente. Para resolver isso, o proxy injeta cabeçalhos HTTP:

X-Forwarded-For: 200.150.0.5, 10.0.0.1
X-Forwarded-Proto: https
X-Real-IP: 200.150.0.5

O padrão moderno é o Forwarded (RFC 7239), mais estruturado:

Forwarded: for=200.150.0.5;proto=https;by=10.0.0.1

Connection Tracking no Kernel

O Linux mantém a tabela conntrack (/proc/net/nf_conntrack) com todas as conexões NAT ativas. Cada entrada consome ~300 bytes. Em servidores de alto tráfego, é comum ajustar:

echo "net.netfilter.nf_conntrack_max = 1048576" >> /etc/sysctl.conf
sysctl -p

Quando a tabela enche, novas conexões são derrubadas e o cliente vê timeouts intermitentes.

6. Inspeção Prática

Ver a porta de origem escolhida pelo kernel

# Mostra sockets TCP ativos com porta de origem
ss -tn

# Acompanha em tempo real novas conexões
ss -tn state established '( dport = :80 or sport = :80 )'

Exemplo de saída:

State   Recv-Q Send-Q Local Address:Port    Peer Address:Port
ESTAB   0      0      192.168.1.10:51000    93.184.216.34:80
ESTAB   0      0      192.168.1.10:51001    93.184.216.34:80

Capturar com tcpdump para ver o cabeçalho

sudo tcpdump -ni eth0 -nn 'tcp and port 80' -X | head -20

Os primeiros 4 bytes após o cabeçalho Ethernet+IP são as portas TCP. O Wireshark decodifica visualmente.

No lado do servidor (NGINX)

log_format main '$remote_addr:$remote_port -> $server_addr:$server_port '
                '"$request" $status';
access_log /var/log/nginx/access.log main;

A variável $remote_port contém a porta efêmera do cliente — útil para correlacionar logs de acesso com capturas de pacotes.

7. Conexões Simultâneas e Limites

Limite do Servidor

Em Linux, cada conexão TCP ocupa um slot na tabela de sockets do kernel. O limite de file descriptors por processo (default 1024) costuma ser o primeiro gargalo. Em servidores de produção:

ulimit -n 65535                  # processo
echo "* soft nofile 65535" >> /etc/security/limits.conf
echo "fs.file-max = 2097152" >> /etc/sysctl.conf

Problema das Portas Esgotadas (TIME_WAIT)

Quando o servidor fecha a conexão, a porta entra em TIME_WAIT por 60–120 segundos (2 × MSL, RFC 793). Em servidores de alto volume, isso esgota as portas efêmeras (apenas ~28 mil disponíveis):

# Verificar
ss -s

# Mitigações
echo "net.ipv4.tcp_tw_reuse = 1" >> /etc/sysctl.conf   # reutiliza TIME_WAIT
echo "net.ipv4.tcp_fin_timeout = 15" >> /etc/sysctl.conf

8. Tabela Resumo

Conceito Detalhe
Campo TCP Bytes 0–1 do cabeçalho TCP
Faixa efêmera Linux 32768–60999
Faixa efêmera Windows 49152–65535
Quádrupla socket {IP_src, Port_src, IP_dst, Port_dst}
Identificação de sessão HTTP Cookies (não IP+porta)
Cabeçalho de proxy X-Forwarded-For, Forwarded
Tabela NAT (Linux) /proc/net/nf_conntrack

9. Conclusão

Descobrir a porta do cliente é trivial do ponto de vista de protocolo — basta ler 2 bytes do cabeçalho TCP —, mas os desdobramentos operacionais são profundos. Em ambientes modernos com NAT, proxies, load balancers e CDNs, a porta de origem visível ao servidor raramente é a porta original do cliente. Engenheiros precisam entender essa cadeia de traduções para diagnosticar problemas de sessão, persistência (sticky sessions), auditoria de acesso e segurança (rate limiting por IP). Saber que a porta efêmera é escolhida pelo kernel, que o servidor a obtém do cabeçalho TCP e que ela não é confiável como identificador persistente é fundamental para arquiteturas de aplicação robustas.