Depuis la page de manuel:
SO_REUSEADDR Spécifie que les règles utilisées pour valider les adresses fournies à bind () doivent permettre la réutilisation des adresses locales, si cela est pris en charge par le protocole. Cette option prend une valeur int. Ceci est une option booléenne
Quand devrais-je l'utiliser? Pourquoi la "réutilisation des adresses locales" donne-t-elle?
Le principal objectif de conception de TCP est de permettre une communication de données fiable face à la perte de paquets, à la réorganisation des paquets et - clé, ici - à la duplication de paquets.
Il est assez évident comment une pile réseau TCP/IP gère tout cela pendant que la connexion est établie, mais il y a un cas Edge qui se produit juste après la fermeture de la connexion. Que se passe-t-il si un paquet envoyé juste à la fin de la conversation est dupliqué et retardé, de telle sorte que l'arrêt à 4 voies les paquets parviennent au récepteur avant le paquet retardé? La pile ferme consciencieusement sa connexion. Plus tard, le paquet en double retardé apparaît. Que doit faire la pile?
Plus important encore, que devrait-il faire si un programme avec des sockets ouverts sur une adresse IP donnée + TCP port ferme ses sockets, puis un bref instant plus tard, un programme arrive et veut écouter sur cette même adresse IP et TCP numéro de port? (Cas typique: un programme est tué et est rapidement redémarré.)
Il y a deux choix:
Interdisez la réutilisation de ce combo IP/port pendant au moins 2 fois la durée maximale pendant laquelle un paquet peut être en vol. Dans TCP, cela s'appelle généralement le délai 2 × MSL . Vous voyez parfois aussi 2 × RTT , ce qui est à peu près équivalent.
Il s'agit du comportement par défaut de toutes les piles TCP/IP courantes. 2 × MSL est généralement compris entre 30 et 120 secondes, et il apparaît dans la sortie netstat
comme la période TIME_WAIT
. Passé ce délai, la pile suppose que tous les paquets non autorisés ont été abandonnés en route en raison de l'expiration TTLs , de sorte que le socket quitte l'état TIME_WAIT
, permettant à ce combo IP/port d'être réutilisé.
Autorisez le nouveau programme à se lier à nouveau à ce combo IP/port. Dans les piles avec sockets BSD interfaces - essentiellement tous les systèmes Unix et Unix, plus Windows via Winsock - vous devez demander ce comportement en définissant le SO_REUSEADDR
via setsockopt()
avant d'appeler bind()
.
SO_REUSEADDR
Est le plus souvent défini dans les programmes de serveur réseau, car un modèle d'utilisation courant consiste à effectuer une modification de configuration, puis à redémarrer ce programme pour que la modification prenne effet. Sans SO_REUSEADDR
, L'appel bind()
dans la nouvelle instance du programme redémarré échouera s'il y avait des connexions ouvertes à l'instance précédente lorsque vous l'avez tuée. Ces connexions contiendront le port TCP dans l'état TIME_WAIT
Pendant 30 à 120 secondes, vous tombez donc dans le cas 1 ci-dessus.
Le risque de définir SO_REUSEADDR
Est qu'il crée une ambiguïté: les métadonnées dans les en-têtes d'un paquet TCP TCP ne sont pas suffisamment uniques pour que la pile puisse dire de manière fiable si le paquet est périmé et devrait donc être abandonné plutôt que remis à la nouvelle prise d'écoute car il était clairement destiné à un auditeur désormais mort.
Si vous ne voyez pas que cela est vrai, voici tout ce que la pile TCP/IP de la machine d'écoute doit travailler avec par connexion pour prendre cette décision:
IP locale: Pas unique par connexion. En fait, notre définition de problème ici dit que nous réutilisons délibérément l'IP locale.
Local TCP port: Idem.
IP distante: La machine à l'origine de l'ambiguïté peut se reconnecter, ce qui n'aide pas à lever l'ambiguïté de la destination appropriée du paquet.
Port distant: Dans les piles de réseau bien comportées, le port distant d'une connexion sortante n'est pas réutilisé rapidement, mais il n'est que de 16 bits, donc vous ' Nous avons 30 à 120 secondes pour forcer la pile à passer par quelques dizaines de milliers de choix et à réutiliser le port. Les ordinateurs pouvaient fonctionner aussi rapidement dans les années 1960.
Si votre réponse à cela est que la pile distante devrait faire quelque chose comme TIME_WAIT
De son côté pour interdire éphémère TCP port réutilisation, cette solution suppose que l'hôte distant est bénin. Un acteur malveillant est libre de réutiliser ce port distant.
Je suppose que la pile de l'auditeur pourrait choisir de strictement interdire les connexions à partir du TCP 4-Tuple uniquement, de sorte que pendant l'état TIME_WAIT
Un hôte distant donné ne puisse pas se reconnecter avec le même port éphémère distant, mais je ne suis au courant d'aucune pile TCP avec ce raffinement particulier.
Local et distant TCP numéros de séquence: Ceux-ci ne sont pas non plus suffisamment uniques pour qu'un nouveau programme distant ne puisse pas apparaître avec les mêmes valeurs.
Si nous redessinions TCP aujourd'hui, je pense que nous intégrerions TLS ou quelque chose comme ça en tant que non fonctionnalité optionnelle, dont l'un des effets est de rendre impossible ce type de détournement de connexion involontaire et malveillant, mais qui nécessite l'ajout de grands champs (128 bits et plus), ce qui n'était pas du tout pratique en 1981, lorsque le document de la version actuelle de TCP ( RFC 79 ) a été publié.
Sans un tel renforcement, l'ambiguïté créée en autorisant une nouvelle liaison pendant TIME_WAIT
Signifie que vous pouvez soit a) faire en sorte que les données périmées destinées à l'ancien écouteur soient mal envoyées à une socket appartenant au nouvel écouteur, rompant ainsi le protocole de l'auditeur ou l'injection incorrecte de données périmées dans la connexion; ou b) de nouvelles données pour la nouvelle prise d'écoute affectées par erreur à l'ancienne prise d'auditeur et donc supprimées par inadvertance.
La chose sûre à faire est d'attendre la période TIME_WAIT
.
En fin de compte, cela se résume à un choix de coûts: attendre la période TIME_WAIT
Ou prendre le risque de perte de données indésirables ou d'injection de données par inadvertance.
De nombreux programmes serveur prennent ce risque, décidant qu'il est préférable de sauvegarder le serveur immédiatement afin de ne pas manquer plus de connexions entrantes que nécessaire.
Ce n'est pas un choix universel. De nombreux programmes - même les programmes serveur nécessitant un redémarrage pour appliquer une modification des paramètres - choisissent plutôt de laisser SO_REUSEADDR
Seul. Le programmeur peut connaître ces risques et choisit de laisser la valeur par défaut, ou il peut ignorer les problèmes mais bénéficie d'une valeur par défaut judicieuse.
Certains programmes réseau offrent à l'utilisateur un choix parmi les options de configuration, évitant ainsi la responsabilité à l'utilisateur final ou à l'administrateur système.
SO_REUSEADDR permet à votre serveur de se lier à une adresse qui se trouve dans un
État TIME_WAIT.
Cette option de socket indique au noyau que même si ce port est occupé (dans l'état TIME_WAIT), continuez et réutilisez-le quand même. S'il est occupé, mais avec un autre état, vous obtiendrez toujours une erreur d'adresse déjà utilisée. Il est utile si votre serveur a été arrêté, puis redémarré immédiatement alors que les sockets sont toujours actifs sur son port.
De nixguide.net
Lorsque vous créez un socket, vous ne le possédez pas vraiment. Le système d'exploitation (pile TCP) le crée pour vous et vous donne un descripteur (descripteur de fichier) pour y accéder. Lorsque votre socket est fermé, il faut du temps pour que le système d'exploitation le "ferme complètement" pendant qu'il passe par plusieurs états. Comme EJP l'a mentionné dans les commentaires, le délai le plus long provient généralement de l'état TIME_WAIT. Ce délai supplémentaire est nécessaire pour gérer les cas Edge à la toute fin de la séquence de terminaison et s'assurer que le dernier accusé de réception de terminaison est passé ou que l'autre côté s'est réinitialisé en raison d'un délai d'attente. Ici vous pouvez trouver quelques considérations supplémentaires sur cet état. Les principales considérations sont signalées comme suit:
N'oubliez pas que TCP garantit que toutes les données transmises seront livrées, si possible. Lorsque vous fermez un socket, le serveur passe dans un état TIME_WAIT, juste pour être vraiment vraiment sûr que toutes les données ont Lorsqu'une prise est fermée, les deux parties conviennent en s'envoyant des messages qu'elles n'enverront plus de données. Cela m'a semblé suffisant, et une fois la prise de contact terminée, la prise doit être fermée. Le problème est double. Premièrement, il n'y a aucun moyen de s'assurer que le dernier accusé de réception a été communiqué avec succès. Deuxièmement, il peut y avoir des "doublons errants" sur le net qui doivent être traités s'ils sont livrés.
Si vous essayez de créer plusieurs sockets avec la même paire ip: port très rapidement, vous obtenez l'erreur "adresse déjà utilisée" car le socket précédent n'aura pas été entièrement libéré. L'utilisation de SO_REUSEADDR supprimera cette erreur car elle remplacera les vérifications de toute instance précédente.