Escuta TCP / HTTP nas portas: como muitos usuários podem compartilhar a mesma porta
Então, o que acontece quando um servidor escuta conexões de entrada em uma porta TCP? Por exemplo, digamos que você tenha um servidor web na porta 80. Vamos supor que seu computador tenha o endereço IP público 24.14.181.229 e a pessoa que tenta se conectar a você tem o endereço IP 10.1.2.3. Essa pessoa pode se conectar a você abrindo um soquete TCP para 24.14.181.229:80. Simples o suficiente.
Intuitivamente (e erroneamente), a maioria das pessoas presume que seja algo assim:
Local Computer | Remote Computer
--------------------------------
<local_ip>:80 | <foreign_ip>:80
^^ not actually what happens, but this is the conceptual model a lot of people have in mind.
Isso é intuitivo, pois do ponto de vista do cliente, ele possui um endereço IP, e se conecta a um servidor em IP: PORT. Já que o cliente se conecta à porta 80, a porta dele também deve ser 80? É uma coisa sensata de se pensar, mas na verdade não é o que acontece. Se isso fosse correto, poderíamos servir apenas um usuário por endereço IP estrangeiro. Depois que um computador remoto se conecta, ele monopoliza a conexão da porta 80 para a porta 80 e ninguém mais consegue se conectar.
Três coisas devem ser entendidas:
1.) Em um servidor, um processo está escutando em uma porta. Assim que consegue uma conexão, ele passa para outro segmento. A comunicação nunca monopoliza a porta de escuta.
2.) As conexões são identificadas exclusivamente pelo sistema operacional pela seguinte 5-tupla: (local-IP, local-porta, remoto-IP, porta remota, protocolo). Se qualquer elemento da tupla for diferente, então esta é uma conexão completamente independente.
3.) Quando um cliente se conecta a um servidor, ele escolhe uma porta de origem de alta ordem aleatória e não utilizada . Dessa forma, um único cliente pode ter até ~ 64k conexões com o servidor para a mesma porta de destino.
Então, isso é realmente o que é criado quando um cliente se conecta a um servidor:
Local Computer | Remote Computer | Role
-----------------------------------------------------------
0.0.0.0:80 | <none> | LISTENING
127.0.0.1:80 | 10.1.2.3:<random_port> | ESTABLISHED
Olhando para o que realmente acontece
Primeiro, vamos usar o netstat para ver o que está acontecendo neste computador. Usaremos a porta 500 em vez de 80 (porque um monte de coisas está acontecendo na porta 80, pois é uma porta comum, mas funcionalmente não faz diferença).
netstat -atnp | grep -i ":500 "
Como esperado, a saída está em branco. Agora vamos iniciar um servidor web:
sudo python3 -m http.server 500
Agora, aqui está o resultado da execução de netstat novamente:
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:500 0.0.0.0:* LISTEN -
Portanto, agora existe um processo que está ouvindo ativamente (Estado: LISTEN) na porta 500. O endereço local é 0.0.0.0, que é o código para "ouvir todos os endereços IP". Um erro fácil de cometer é escutar apenas na porta 127.0.0.1, que só aceita conexões do computador atual. Portanto, esta não é uma conexão, isso significa apenas que um processo solicitou o bind () ao IP da porta, e esse processo é responsável por lidar com todas as conexões para essa porta. Isso sugere a limitação de que só pode haver um processo por computador ouvindo em uma porta (há maneiras de contornar isso usando a multiplexação, mas este é um tópico muito mais complicado). Se um servidor web estiver escutando na porta 80, ele não pode compartilhar essa porta com outros servidores web.
Agora, vamos conectar um usuário à nossa máquina:
quicknet -m tcp -t localhost:500 -p Test payload.
Este é um script simples ( https://github.com/grokit/quickweb ) que abre um soquete TCP, envia a carga ("Carga de teste." Neste caso), espera alguns segundos e se desconecta. Executar netstat novamente enquanto isso está acontecendo exibe o seguinte:
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:500 0.0.0.0:* LISTEN -
tcp 0 0 192.168.1.10:500 192.168.1.13:54240 ESTABLISHED -
Se você se conectar a outro cliente e executar o netstat novamente, verá o seguinte:
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:500 0.0.0.0:* LISTEN -
tcp 0 0 192.168.1.10:500 192.168.1.13:26813 ESTABLISHED -
... ou seja, o cliente usou outra porta aleatória para a conexão. Portanto, nunca há confusão entre os endereços IP.