Pourquoi la longueur du chemin de socket est-elle limitée à une centaine de caractères?

18

Sur les systèmes Unix, les noms de chemin n'ont généralement pratiquement aucune limitation de longueur (enfin, 4096 caractères sous Linux) ... à l'exception des chemins de fichiers socket qui sont limités à environ 100 caractères (107 caractères sous Linux ).

  • Première question: pourquoi une si faible limitation?

J'ai vérifié qu'il semble possible de contourner cette limitation en changeant le répertoire de travail actuel et en créant dans divers répertoires plusieurs fichiers socket utilisant tous le même chemin ./myfile.sock: les applications clientes semblent se connecter correctement aux processus serveur attendus même si lsoftout montre d'entre eux écoutant sur le même chemin de fichier socket.

  • Cette solution de contournement est-elle fiable ou ai-je simplement eu de la chance?
  • Ce comportement est-il spécifique à Linux ou cette solution de contournement peut-elle également s'appliquer à d'autres Unix?
WhiteWinterWolf
la source
La limite est encore plus basse (104) sur les systèmes OpenBSD actuels ou Mac OS X 10.11.
thrig
L'important, c'est qu'il doit être inférieur à 108, pour des raisons de compatibilité :)
AFAIK c'est 108 caractères sur Linux. Veuillez vérifier /usr/include/$arch-linux-gnu/sys/un.h sur votre machine.
schaiba
@schaiba: 108 octets, ce qui signifie une chaîne de 107 caractères terminée par un terminateur nul.
WhiteWinterWolf

Réponses:

18

Compatibilité avec d'autres plates-formes ou compatibilité avec des éléments plus anciens pour éviter les dépassements lors de l'utilisation de snprintf()et strncpy().

Michael Kerrisk explique dans son livre à la page 1165 - Chapitre 57, Sockets: domaine Unix:

SUSv3 ne spécifie pas la taille du champ sun_path. Les premières implémentations BSD utilisaient 108 et 104 octets, et une implémentation contemporaine (HP-UX 11) utilise 92 octets. Les applications portables doivent coder sur cette valeur inférieure et utiliser snprintf () ou strncpy () pour éviter les dépassements de tampon lors de l'écriture dans ce champ.

Les gars de Docker s'en sont même moqués, car certains sockets comptaient 110 caractères:

C'est pourquoi LINUX utilise une prise de 108 caractères. Cela pourrait-il être changé? Bien sûr. Et c'est la raison pour laquelle, en premier lieu, cette limitation a été créée sur les anciens systèmes d'exploitation:

Citant la réponse:

Il devait correspondre à l'espace disponible dans une structure de données de noyau pratique.

Citant «La conception et la mise en œuvre du système d'exploitation 4.4BSD» par McKusick et. Al. (page 369):

Les fonctions de gestion de la mémoire tournent autour d'une structure de données appelée mbuf. Les Mbufs, ou tampons de mémoire, ont une longueur de 128 octets, 100 ou 108 octets de cet espace étant réservés au stockage de données.

Autres systèmes d'exploitation (sockets de domaine Unix):


la source
1
SUSv3 XNET était silencieux car il n'y avait pas de consensus sur la question.
fpmurphy
Avez-vous un lien pour prouver votre point de vue?
Merci pour cette réponse. Est-il fiable d'utiliser plusieurs fichiers socket portant des noms identiques par rapport à différents répertoires de travail (par exemple, créer un fichier sockets nommé ./my.socketci-dessous répertoire A/et un autre fichier socket également nommé ./my.socketci-dessous répertoire B/)? lsofne fait aucune distinction entre les deux fichiers socket, mais il semble toujours fonctionner mais je me demande si c'est juste parce que j'ai de la chance. Ce serait une bonne solution de contournement pour créer des fichiers socket sous un chemin qui est déjà plus long que la taille autorisée.
WhiteWinterWolf
La recherche de sockets unix sur mon serveur de messagerie semble apporter le nom complet du chemin: lsof -U| grep amavis( amavis-se 2708 zimbra 17u unix 0xffff8806c0a95400 0t0 310330411 /opt/zimbra/data/tmp/amavisd-zmq.sock
Oui, je sais que c'est inhabituel, d'où ma question ici;)! Pour ce que j'ai testé, les noms relatifs fonctionnent, mais cela me semble toujours étrange ... mais cela fonctionne. Mon application n'est pas à l'échelle du système, donc les fichiers de socket sont stockés avec toutes les autres données d'application dans un emplacement contrôlé par l'utilisateur, ce qui est fortement préféré mais avec un chemin potentiellement trop long, ou je peux encombrer /tmpavec des tonnes de répertoires non supprimés nommés de manière unique chacun contenant un seul fichier socket (tout à fait laid, mais portable et sécurisé).
WhiteWinterWolf
5

Concernant le pourquoi, nwildner a déjà écrit une excellente réponse .

Ici, je vais me concentrer uniquement sur le comment et l'utilisation relative du chemin.

En interne, bien que le fichier socket puisse également être recherché par son nom (je suppose), il est généralement recherché par inode. Sous Linux, cette recherche est assurée par la fonction unix_find_socket_byinode()définie dans net / unix / af_unix.c .

Cela peut être facilement vérifié comme suit:

  • Créez deux répertoires A / et B / .
  • Sous chaque répertoire, faites un processus d'écoute sur les fichiers socket portant le même nom. Avec socatvous utilisez une commande telle que:
$ socat UNIX-LISTEN:./my.sock -
  • Échangez maintenant les fichiers socket en déplaçant A / my.sock vers B / et vice-versa.
  • Désormais, si l'application cliente se connecte à A / my.sock, elle contactera le serveur B et si elle se connecte à B / my.sock, elle contactera le serveur A (notez cependant que lorsque la communication se termine, le processus serveur peut supprimer légitimement ce qu'il pense être son propre fichier socket).

J'ai vérifié ce comportement sur une poignée de systèmes Unix (Linux Debian, FreeBSD et OpenIndiana pour obtenir une certaine diversité), donc ce comportement semble être au moins très répandu, sinon standard.

Les chemins absolus sont généralement utilisés comme convention entre le client et les processus serveur, car le processus client peut autrement ne pas savoir comment établir la communication initiale avec le serveur.

Cependant, si cette communication initiale n'est pas un problème, il semble donc sûr d'utiliser des chemins relatifs pour la création de fichiers socket, ce qui permet d'éviter les problèmes de longueur de chemin lorsque l'emplacement du fichier socket n'est pas directement contrôlé par le processus serveur.

WhiteWinterWolf
la source