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 ?

6 réponses

1 2
Avatar
Stephane Chazelas
2007-07-14, 11:35(+00), 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.


Oui, mais ce n'est qu'un exemple, quid de mountd, nfsd, cvs
pserver, oracle, mysql...

--
Stéphane


Avatar
Stephane Chazelas
2007-07-14, 12:25(+00), Stephane Chazelas:
2007-07-14, 11:35(+00), 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.


Oui, mais ce n'est qu'un exemple, quid de mountd, nfsd, cvs
pserver, oracle, mysql...


Experience amusante:

duey:~$ rpcinfo -p | grep tcp | grep mountd
100005 1 tcp 32775 mountd
100005 2 tcp 32775 mountd
100005 3 tcp 32775 mountd
duey:~$ perl -MSocket -e 'socket A, PF_INET, SOCK_STREAM,
getprotobyname("tcp"); setsockopt(A, SOL_SOCKET, SO_REUSEADDR, 1); bind(A,
sockaddr_in(32775, inet_aton("duey"))); listen (A, 1000); sleep' &
[1] 11806

Et hop, plus personne ne peut monter les nfs de duey.

--
Stéphane



Avatar
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).


C'est non seulement probable, mais même certain. Pardon de ne pas avoir
été clair sur ce point.

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.


Non, en effet. Il n'y a rien à changer à celui qui bind sur INADDR_ANY.
Mais là n'était pas ma question.

Ma question était : peut-on faire un SO_REUSEADDR sans être root, ce
qui permettrait de « voler » les ports supérieurs à 1024 sans avoir de
droits particuliers ?

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.


La session X est basée sur UDP et non TCP ? Avec un protocole connecté
tel que TCP il sera impossible de s'intercaler dans un dialogue en cours
puisque les quatre infos discriminantes (adresse et port locaux, adresse
et port distants) sont complètement déterminés après la connexion.

Le comportement de Linux me semble plus sain.


En tout cas, merci de l'info comme quoi ça ne marche pas sur Linux.



Avatar
Stephane Chazelas
2007-07-14, 16:56(+02), Olivier Miakinen:
[...]
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.


Non, en effet. Il n'y a rien à changer à celui qui bind sur INADDR_ANY.
Mais là n'était pas ma question.

Ma question était : peut-on faire un SO_REUSEADDR sans être root, ce
qui permettrait de « voler » les ports supérieurs à 1024 sans avoir de
droits particuliers ?


On peut faire le setsockopt, mais pas le bind.

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.


La session X est basée sur UDP et non TCP ? Avec un protocole connecté
tel que TCP il sera impossible de s'intercaler dans un dialogue en cours
puisque les quatre infos discriminantes (adresse et port locaux, adresse
et port distants) sont complètement déterminés après la connexion.
[...]


Non, bien sur, mais je peux a partir d'un moment faire en sorte
que toute nouvelle connection passe par mon "man in the middle",
par exemple, que le prochain xterm que lancera la victime, se
connectera a mon intercepteur.

En ayant DISPLAY=host:0, la victime aimerait pouvoir etre
guarantie qu'elle se connectera au serveur X qu'elle a sous les
yeux, mais en fait ce SO_REUSEADDR permet a quelqu'un de
preempter le port TCP pour une addresse donnee.

--
Stéphane


Avatar
Nicolas George
Stephane Chazelas wrote in message
:
Oui, mais ce n'est qu'un exemple, quid de mountd, nfsd, cvs
pserver, oracle, mysql...


Ça pourrait être résolu en n'autorisant à partager un port dans ces
conditions que si l'UID est la même.

Avatar
Luc.Habert.00__arjf
Nicolas George :

Ça pourrait être résolu en n'autorisant à partager un port dans ces
conditions que si l'UID est la même.


Ça mériterait reflexion profonde. Que fais-tu si les EUID, RUID, saved UID
ne sont pas identiques? Et les capabilities? Et si l'un des programmes était
en mode 711 appartenant à un autre utilisateur? Et si il était sgid? Etc...
L'UID seul n'est pas une définition claire de la personne à qui appartient
le process.

1 2