TCP / HTTP à l'écoute sur les ports : Comment plusieurs utilisateurs peuvent-ils partager le même port ?
Que se passe-t-il donc lorsqu'un serveur écoute les connexions entrantes sur un port TCP ? Par exemple, disons que vous avez un serveur web sur le port 80. Supposons que votre ordinateur ait l'adresse IP publique 24.14.181.229 et que la personne qui tente de se connecter à vous ait l'adresse IP 10.1.2.3. Cette personne peut se connecter à vous en ouvrant une socket TCP vers 24.14.181.229:80. C'est assez simple.
Intuitivement (et à tort), la plupart des gens pensent qu'il ressemble à ceci :
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.
C'est intuitif, car du point de vue du client, il a une adresse IP et se connecte à un serveur à l'adresse IP:PORT. Puisque le client se connecte au port 80, son port doit également être 80 ? C'est une idée raisonnable, mais ce n'est pas ce qui se passe. Si c'était le cas, nous ne pourrions servir qu'un seul utilisateur par adresse IP étrangère. Une fois qu'un ordinateur distant se connecte, il monopolise la connexion entre le port 80 et le port 80, et personne d'autre ne peut se connecter.
Il faut comprendre trois choses :
1.) Sur un serveur, un processus est l'écoute sur un port. Une fois qu'il a obtenu une connexion, il la transmet à un autre thread. La communication ne monopolise jamais le port d'écoute.
2.) Les connexions sont identifiées de manière unique par le système d'exploitation au moyen du 5-tuple suivant : (local-IP, local-port, remote-IP, remote-port, protocole). Si l'un des éléments du tuple est différent, il s'agit d'une connexion totalement indépendante.
3.) Lorsqu'un client se connecte à un serveur, il choisit un port source aléatoire et inutilisé d'ordre supérieur . De cette façon, un seul client peut avoir jusqu'à ~64k connexions au serveur pour le même port de destination.
C'est donc ce qui est créé lorsqu'un client se connecte à un serveur :
Local Computer | Remote Computer | Role
-----------------------------------------------------------
0.0.0.0:80 | <none> | LISTENING
127.0.0.1:80 | 10.1.2.3:<random_port> | ESTABLISHED
Regarder ce qui se passe réellement
Tout d'abord, utilisons netstat pour voir ce qui se passe sur cet ordinateur. Nous utiliserons le port 500 au lieu de 80 (parce que tout un tas de choses se passent sur le port 80 car c'est un port courant, mais fonctionnellement, cela ne fait pas de différence).
netstat -atnp | grep -i ":500 "
Comme prévu, la sortie est vide. Démarrons maintenant un serveur web :
sudo python3 -m http.server 500
Voici maintenant le résultat de l'exécution de netstat à nouveau :
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:500 0.0.0.0:* LISTEN -
Il y a donc maintenant un processus qui écoute activement (State : LISTEN) sur le port 500. L'adresse locale est 0.0.0.0, ce qui signifie "écoute de toutes les adresses IP". Une erreur facile à commettre est de n'écouter que sur le port 127.0.0.1, qui n'acceptera que les connexions provenant de l'ordinateur actuel. Il ne s'agit donc pas d'une connexion, cela signifie simplement qu'un processus a demandé à bind() sur le port IP, et que ce processus est responsable de la gestion de toutes les connexions sur ce port. Cela renvoie à la limitation selon laquelle il ne peut y avoir qu'un seul processus par ordinateur écoutant sur un port (il existe des moyens de contourner ce problème en utilisant le multiplexage, mais c'est un sujet beaucoup plus compliqué). Si un serveur web écoute sur le port 80, il ne peut pas partager ce port avec d'autres serveurs web.
Maintenant, connectons un utilisateur à notre machine :
quicknet -m tcp -t localhost:500 -p Test payload.
Il s'agit d'un simple script ( https://github.com/grokit/quickweb ) qui ouvre une socket TCP, envoie la charge utile ("Test payload." dans ce cas), attend quelques secondes et se déconnecte. Si l'on refait netstat pendant que cela se produit, on obtient le résultat suivant :
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 -
Si vous vous connectez avec un autre client et que vous exécutez à nouveau netstat, vous verrez ce qui suit :
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 -
... c'est-à-dire que le client a utilisé un autre port aléatoire pour la connexion. Il n'y a donc jamais de confusion entre les adresses IP.