Dlaczego długość ścieżki gniazda jest ograniczona do stu znaków?


18

W systemach uniksowych nazwy ścieżek zwykle nie mają praktycznie żadnego ograniczenia długości (cóż, 4096 znaków w systemie Linux) ... z wyjątkiem ścieżek plików gniazd, które są ograniczone do około 100 znaków (107 znaków w systemie Linux ).

  • Pierwsze pytanie: dlaczego tak niskie ograniczenie?

Sprawdziłem, czy można obejść to ograniczenie, zmieniając bieżący katalog roboczy i tworząc w różnych katalogach kilka plików gniazd przy użyciu tej samej ścieżki ./myfile.sock: aplikacje klienckie wydają się poprawnie łączyć z oczekiwanymi procesami serwera, chociaż lsofpokazuje wszystkie z nich nasłuchuje na tej samej ścieżce pliku gniazda.

  • Czy to obejście jest niezawodne, czy miałem szczęście?
  • Czy to zachowanie jest specyficzne dla Linuksa, czy może to obejście dotyczy również innych Uniksów?

Limit jest jeszcze niższy (104) w obecnych systemach OpenBSD lub Mac OS X 10.11.
thrig

Ważną rzeczą jest to, że ze względu na kompatybilność musi być niższy niż 108 :)

AFAIK to 108 znaków w Linuksie. Sprawdź /usr/include/$arch-linux-gnu/sys/un.h na swoim komputerze.
schaiba

@schaiba: 108 bajtów, co oznacza łańcuch 107 znaków zakończony terminatorem zerowym.
WhiteWinterWolf

Odpowiedzi:


18

Zgodność z innymi platformami lub kompatybilność ze starszymi urządzeniami, aby uniknąć przekroczeń podczas używania snprintf()i strncpy().

Michael Kerrisk wyjaśnia w swojej książce na stronie 1165 - Rozdział 57, Gniazda: Domena Unix:

SUSv3 nie określa wielkości pola sun_path. Wczesne implementacje BSD wykorzystywały 108 i 104 bajty, a jedna współczesna implementacja (HP-UX 11) wykorzystuje 92 bajty. Aplikacje przenośne powinny kodować do tej niższej wartości i używać snprintf () lub strncpy (), aby uniknąć przepełnienia bufora podczas pisania w tym polu.

Ludzie z dokerów nawet się z tego wyśmiewali, ponieważ niektóre gniazda miały długość 110 znaków:

Dlatego LINUX używa gniazda 108 znaków. Czy można to zmienić? Oczywiście. I właśnie dlatego ograniczenie to zostało utworzone w starszych systemach operacyjnych:

Cytując odpowiedź:

Miał pasować do przestrzeni dostępnej w poręcznej strukturze danych jądra.

Cytując „Projekt i wdrożenie systemu operacyjnego 4.4BSD” McKusick i in. glin. (strona 369):

Funkcje zarządzania pamięcią obracają się wokół struktury danych zwanej mbuf. Mbufy lub bufory pamięci mają długość 128 bajtów, przy czym 100 lub 108 bajtów tego miejsca jest zarezerwowanych do przechowywania danych.

Inne systemy operacyjne (gniazda domeny unix):


1
SUSv3 XNET milczał, ponieważ nie było konsensusu w tej sprawie.
fpmurphy

Czy masz link do potwierdzenia swojego punktu widzenia?

Dziękuję za tę odpowiedź. Czy warto używać kilku plików gniazd o identycznych nazwach w stosunku do różnych działających katalogów (na przykład utwórz plik gniazd o nazwie ./my.socketponiżej katalogu A/, a inny plik gniazda o nazwie również ./my.socketponiżej katalogu B/)? lsofnie robi rozróżnienia między dwoma plikami gniazd, jednak wydaje się, że nadal działa, ale zastanawiam się, czy to dlatego, że mam szczęście. Byłoby to dobre obejście, aby utworzyć pliki gniazd poniżej ścieżki, która jest już dłuższa niż dozwolony rozmiar.
WhiteWinterWolf

Wyszukiwanie gniazd unixowych na moim serwerze pocztowym wydaje się przynosić pełną nazwę ścieżki: lsof -U| grep amavis(newline)amavis-se 2708 zimbra 17u unix 0xffff8806c0a95400 0t0 310330411 /opt/zimbra/data/tmp/amavisd-zmq.sock

Tak, wiem, że to niezwykłe, stąd moje pytanie tutaj;)! W przypadku tego, co przetestowałem, nazwy względne działają, ale nadal wydaje mi się to dziwne ... ale działa. Moja aplikacja nie obejmuje całego systemu, więc pliki gniazd są albo przechowywane wraz ze wszystkimi innymi danymi aplikacji w lokalizacji kontrolowanej przez użytkownika, co jest zdecydowanie preferowane, ale z potencjalnie zbyt długą ścieżką, lub mogę zaśmiecać /tmpsię mnóstwem unikalnie nazwanych katalogów zawierający pojedynczy plik gniazda (całkowicie brzydki, ale przenośny i bezpieczny).
WhiteWinterWolf

5

Jeśli chodzi o to, nwildner napisał już doskonałą odpowiedź .

Tutaj skupię się na tym, jak i względne użycie ścieżki.

Wewnętrznie, chociaż plik gniazda można również wyszukać według nazwy (tak sądzę), zwykle są one wyszukiwane według i-węzła. W Linuksie to wyszukiwanie zapewnia funkcja unix_find_socket_byinode()zdefiniowana w net / unix / af_unix.c .

Można to łatwo sprawdzić w następujący sposób:

  • Utwórz dwa katalogi A / i B / .
  • W każdym katalogu uruchom proces nasłuchiwania plików gniazd o tej samej nazwie. Z socatużyłbyś polecenia takiego jak:
$ socat UNIX-LISTEN:./my.sock -
  • Teraz wymień pliki gniazd, przenosząc A / my.sock do B / i odwrotnie.
  • Odtąd, jeśli aplikacja kliencka połączy się z A / my.sock , skontaktuje się z serwerem B , a jeśli połączy się z B / my.sock , skontaktuje się z serwerem A (pamiętaj jednak, że po zakończeniu komunikacji proces serwera może zgodnie z prawem usuń to, co uważa za własny plik gniazda).

Sprawdziłem to zachowanie na kilku systemach uniksowych (Linux Debian, FreeBSD i OpenIndiana, aby uzyskać pewną różnorodność), więc to zachowanie wydaje się być co najmniej szeroko rozpowszechnione, jeśli nie standardowe.

Ścieżki bezwzględne są zwykle używane jako konwencja między procesami klienta i serwera, ponieważ proces klienta może nie wiedzieć, jak ustanowić początkową komunikację z serwerem.

Jeśli jednak ta początkowa komunikacja nie stanowi problemu, wydaje się, że bezpieczne jest używanie ścieżek względnych do tworzenia plików gniazd, co pozwala uniknąć problemów z długością ścieżek, gdy lokalizacja pliku gniazda nie jest bezpośrednio kontrolowana przez proces serwera.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.