Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

SO_REUSEADDR et INADDR_ANY

16 réponses
Avatar
Nicolas George
Il me semblait qu'il était légal d'avoir deux serveurs qui écoutent sur le
même port, un sur une adresse particulière et l'autre sur INADDR_ANY, pour
peu que SO_REUSEADDR soit utilisé.

Stevens confirme (UNP page 195) :

# SO_REUSEADDR allows multiple instances of the same server to be started on
# the same port, as long as each instance binds a different local IP
# address. [...] The first HTTP server would call bind with a local IP
# address of 192.69.10.128 and a local port of 80 [...] The third server
# would call bind with the willcard as the local IP address and a local port
# of 80. Again, SO_REUSEADDR is required for the final call to succeed.

Or sous Linux (2.6.21.4, pour les tests les plus détaillés), ça ne marche
pas. Par exemple, si je lance en parallèle :

strace netcat -l -p 1234
strace netcat -l -s 127.0.0.1 -p 1234

J'obtiens ceci (je simplifie la notation des structures par strace pour que
ce soit plus lisible) :

premier> setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
premier> bind(3, {AF_INET, 1234, 0.0.0.0}, 16) = 0
second> setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
second> bind(3, {AF_INET, 1234, 127.0.0.1), 16) = -1 EADDRINUSE (Address already in use)

Ou, si j'inverse l'ordre de lancement, l'échec est inversé. Si j'ajoute un
-s 10.0.0.1 à celui qui écoute sur le wildcard, ça fonctionne.

Est-ce que c'est moi qui rate quelque chose, ou bien est-ce que c'est Linux
qui fait n'importe quoi ?

10 réponses

1 2
Avatar
Stephane Chazelas
2007-07-12, 09:59(+00), Nicolas George:
Il me semblait qu'il était légal d'avoir deux serveurs qui écoutent sur le
même port, un sur une adresse particulière et l'autre sur INADDR_ANY, pour
peu que SO_REUSEADDR soit utilisé.

Stevens confirme (UNP page 195) :

# SO_REUSEADDR allows multiple instances of the same server to be started on
# the same port, as long as each instance binds a different local IP
# address. [...] The first HTTP server would call bind with a local IP
# address of 192.69.10.128 and a local port of 80 [...] The third server
# would call bind with the willcard as the local IP address and a local port
# of 80. Again, SO_REUSEADDR is required for the final call to succeed.

Or sous Linux (2.6.21.4, pour les tests les plus détaillés), ça ne marche
pas. Par exemple, si je lance en parallèle :
[...]


socket(7) sur une debian:

SO_REUSEADDR
Indicates that the rules used in validating
addresses supplied in a bind(2) call should allow
reuse of local addresses. For PF_INET sockets
this means that a socket may bind, except when
there is an active listening socket bound to the
address. When the listening socket is bound to
INADDR_ANY with a specific port then it is not
possible to bind to this port for any local
address.

--
Stéphane

Avatar
Nicolas George
Stephane Chazelas wrote in message
:
socket(7) sur une debian:


Bien vu, j'avais oublié de regarder là. Donc c'est Linux qui fait n'importe
quoi, et en plus il le fait exprès. Génial.

Avatar
Cyrille Lefevre
Stephane Chazelas wrote in message
:
socket(7) sur une debian:


Bien vu, j'avais oublié de regarder là. Donc c'est Linux qui fait n'importe
quoi, et en plus il le fait exprès. Génial.


non, ce n'est pas linux (quoique :)

il me semble normal que tu ne puisses pas te binder sur INADDR_ANY
et qqc d'autre en même temps sur le même port. comme il est aussi
tout à fait normal de pouvoir ce binder sur le même port sur des
adresses différentes sur un même serveur.

Regards, Cordialement,

Cyrille Lefevre.
--
mailto:Cyrille.Lefevre-news%
supprimer "%nospam% et ".invalid" pour me repondre.
remove "%nospam" and ".invalid" to answer me.


Avatar
Nicolas George
Cyrille Lefevre wrote in message <f765ht$tr7$:
il me semble normal que tu ne puisses pas te binder sur INADDR_ANY
et qqc d'autre en même temps sur le même port.


Pourquoi ? Au contraire, c'est une fonctionnalité tout à fait souhaitable :
un ou plusieurs serveurs sur des adresses particulières, et un autre qui
récupère le reste, c'est quelque chose de tout à fait naturel.

D'autre part, comme je le mentionne dans mon message original, ce
comportement est historiquement permis sous Unix.

Avatar
Stephane Chazelas
2007-07-12, 21:34(+00), Nicolas George:
Cyrille Lefevre wrote in message <f765ht$tr7$:
il me semble normal que tu ne puisses pas te binder sur INADDR_ANY
et qqc d'autre en même temps sur le même port.


Pourquoi ? Au contraire, c'est une fonctionnalité tout à fait souhaitable :
un ou plusieurs serveurs sur des adresses particulières, et un autre qui
récupère le reste, c'est quelque chose de tout à fait naturel.

D'autre part, comme je le mentionne dans mon message original, ce
comportement est historiquement permis sous Unix.


C'est permis au moins sous HPUX et Solaris.

Cela dit, je trouve ca un peu douteux. Ca veut dire que
quelqu'un peut piquer le port de quelqu'un d'autre pour peu que
ce quelqu'un d'autre a fait un bind sur INADDR_ANY avec
SO_REUSEADDR.

--
Stéphane


Avatar
Nicolas George
Stephane Chazelas wrote in message
:
Cela dit, je trouve ca un peu douteux. Ca veut dire que
quelqu'un peut piquer le port de quelqu'un d'autre pour peu que
ce quelqu'un d'autre a fait un bind sur INADDR_ANY avec
SO_REUSEADDR.


De toutes façons, compter sur l'allocation des ports non-privilégier, c'est
forcément non-fiable.

Avatar
Stephane Chazelas
2007-07-12, 22:08(+00), Nicolas George:
Stephane Chazelas wrote in message
:
Cela dit, je trouve ca un peu douteux. Ca veut dire que
quelqu'un peut piquer le port de quelqu'un d'autre pour peu que
ce quelqu'un d'autre a fait un bind sur INADDR_ANY avec
SO_REUSEADDR.


De toutes façons, compter sur l'allocation des ports non-privilégier, c'est
forcément non-fiable.


Comme 6000, 1080... ?

Je viens de verifier, sous Solaris 7 au moins, il y a pas mal de
ports que je peux masquer de la sorte.

--
Stéphane


Avatar
Olivier Miakinen

D'autre part, comme je le mentionne dans mon message original, ce
comportement est historiquement permis sous Unix.


C'est permis au moins sous HPUX et Solaris.


Je le faisais déjà en 1990 sur Unix SCO, et HPUX, et depuis longtemps
sur Solaris et AIX, pour étendre la MIB d'agents SNMP dont nous n'avions
pas le code source. D'ailleurs le code TCP/IP dans le noyau prévoyait
spécifiquement ce cas en comptant le nombre de « wildcards » utilisés
pour résoudre l'adresse.

Cela dit, je trouve ca un peu douteux. Ca veut dire que
quelqu'un peut piquer le port de quelqu'un d'autre pour peu que
ce quelqu'un d'autre a fait un bind sur INADDR_ANY avec
SO_REUSEADDR.


Oui. Dans le cas de SNMP (port 161) il fallait quand même être root
pour pouvoir faire le bind(). Je ne sais pas si ce setsockopt réclame
lui-même les droits de root lorsque le bind ne l'exige pas.


Avatar
Stephane Chazelas
2007-07-14, 01:11(+02), Olivier Miakinen:
[...]
Cela dit, je trouve ca un peu douteux. Ca veut dire que
quelqu'un peut piquer le port de quelqu'un d'autre pour peu que
ce quelqu'un d'autre a fait un bind sur INADDR_ANY avec
SO_REUSEADDR.


Oui. Dans le cas de SNMP (port 161) il fallait quand même être root
pour pouvoir faire le bind(). Je ne sais pas si ce setsockopt réclame
lui-même les droits de root lorsque le bind ne l'exige pas.


C'est probablement parce que 161 est un port privilégié (< 1024).

En l'occurrence, sous Solaris 7, je n'ai meme pas l'impression
qu'il soit necessaire que celui qui bind sur INADDR_ANY le fasse
avec SO_REUSEADDR.

Ca me semble un immense trou de securité, vu que je peux
m'intercaller au beau milieu d'une session X de quelqu'un
d'autre par exemple. Je ne sais pas si ca a ete fixé dans les
versions ulterieures.

Le comportement de Linux me semble plus sain.

--
Stéphane


Avatar
Nicolas George
Stephane Chazelas wrote in message
:
Ca me semble un immense trou de securité, vu que je peux
m'intercaller au beau milieu d'une session X de quelqu'un
d'autre par exemple.


À condition qu'il utilise une socket INET et pas une socket locale, ce qui
devient de plus en plus rare de nos jours.

Je ne sais pas si ca a ete fixé dans les
versions ulterieures.


s/fixé/corrigé/

1 2