Почему длина пути сокета ограничена сотней символов?

18

В Unix-системах имена путей обычно практически не имеют ограничений по длине (ну, 4096 символов в Linux) ... за исключением путей к файлам сокетов, которые ограничены примерно 100 символами (107 символов в Linux ).

  • Первый вопрос: почему такие низкие ограничения?

Я проверил, что кажется возможным обойти это ограничение, изменив текущий рабочий каталог и создав в разных каталогах несколько файлов сокетов, использующих один и тот же путь ./myfile.sock: клиентские приложения, похоже, правильно подключаются к ожидаемым процессам сервера, хотя и lsofотображают все из них прослушивание по одному и тому же пути к файлу сокета.

  • Этот обходной путь надежен или мне просто повезло?
  • Это поведение специфично для Linux или этот обходной путь применим также и к другим Unix?
WhiteWinterWolf
источник
Предел еще ниже (104) в современных системах OpenBSD или Mac OS X 10.11.
thrig
Важно то, что для совместимости он должен быть ниже 108 :)
AFAIK это 108 символов в Linux. Пожалуйста, проверьте /usr/include/$arch-linux-gnu/sys/un.h на вашем компьютере.
Чайба
@schaiba: 108 байт, что означает строку из 107 символов, оканчивающуюся нулевым терминатором.
WhiteWinterWolf

Ответы:

18

Совместимость с другими платформами или совместимость со старыми компонентами, чтобы избежать переполнения при использовании snprintf()и strncpy().

Майкл Керриск объясняет в своей книге на странице 1165 - Глава 57, Сокеты: домен Unix:

SUSv3 не указывает размер поля sun_path. Ранние реализации BSD использовали 108 и 104 байта, а одна современная реализация (HP-UX 11) использует 92 байта. Переносимые приложения должны кодировать это более низкое значение и использовать snprintf () или strncpy (), чтобы избежать переполнения буфера при записи в это поле.

Парни из Docker даже посмеялись над этим, потому что некоторые сокеты имели длину 110 символов:

Вот почему LINUX использует гнездо с 108 символами. Можно ли это изменить? Конечно. И это причина, по которой в первую очередь это ограничение было создано на старых операционных системах:

Цитирую ответ:

Он должен был соответствовать пространству, доступному в удобной структуре данных ядра.

Цитата "Разработка и внедрение операционной системы 4.4BSD" McKusick et. и др. (страница 369):

Средства управления памятью вращаются вокруг структуры данных, называемой mbuf. Mbufs, или буферы памяти, имеют длину 128 байтов, при этом 100 или 108 байтов этого пространства зарезервированы для хранения данных.

Другие ОС (доменные сокеты Unix):


источник
1
SUSv3 XNET молчал, потому что нет единого мнения по этому вопросу.
fpmurphy
Есть ли у вас какая-либо ссылка, подтверждающая вашу точку зрения?
Спасибо за этот ответ. Надежно ли использовать несколько файлов сокетов с одинаковыми именами относительно разных рабочих каталогов (например, создать файл сокетов с именем ./my.socketниже каталога A/, а другой файл сокетов также с именем ./my.socketниже каталога B/)? lsofне делает никаких различий между двумя файлами сокетов, однако, похоже, все еще работает, но мне интересно, если это только потому, что мне повезло. Это был бы хороший обходной путь для создания файлов сокетов ниже пути, который уже длиннее допустимого размера.
WhiteWinterWolf
При поиске сокетов Unix на моем lsof -U| grep amavisamavis-se 2708 zimbra 17u unix 0xffff8806c0a95400 0t0 310330411 /opt/zimbra/data/tmp/amavisd-zmq.sock
Да, я знаю, что это необычно, поэтому мой вопрос здесь;)! Для того, что я тестировал, относительные имена работают, но это все еще кажется мне странным ... но это работает. Мое приложение не является общесистемным, поэтому файлы сокетов либо хранятся со всеми другими данными приложения в контролируемом пользователем месте, что настоятельно рекомендуется, но с потенциально слишком длинным путем, либо я могу загромождать /tmpтоннами неповрежденных каталогов с уникальными именами каждый содержащий один файл сокета (совершенно безобразный, но переносимый и безопасный).
WhiteWinterWolf
5

Что касается того, почему, nwildner уже написал отличный ответ .

Здесь я остановлюсь только на том, как и как использовать относительный путь.

Внутренне, хотя файл сокета также можно искать по имени (я полагаю), он обычно ищется по индоду. В Linux этот поиск обеспечивается функцией, unix_find_socket_byinode()определенной в net / unix / af_unix.c .

Это можно легко проверить следующим образом:

  • Создайте две директории A / и B / .
  • В каждом каталоге заставьте процесс прослушивать файлы сокетов с одинаковыми именами. С socatвами будет использовать команду, такую ​​как:
$ socat UNIX-LISTEN:./my.sock -
  • Теперь обменяйтесь файлами сокетов, переместив A / my.sock в B / и наоборот.
  • С этого момента , если клиентское приложение подключается к A / my.sock, оно связывается с сервером B , а если оно подключается к B / my.sock, оно связывается с сервером A (обратите внимание, что, когда связь заканчивается, процесс сервера может законно удалить то, что он считает своим собственным файлом сокета).

Я проверил это поведение в нескольких системах Unix (Linux Debian, FreeBSD и OpenIndiana, чтобы получить некоторое разнообразие), поэтому такое поведение, по-видимому, является по меньшей мере широко распространенным, если не стандартным.

Абсолютные пути обычно используются в качестве соглашения между клиентским и серверным процессами, поскольку клиентский процесс может иначе не знать, как установить начальную связь с сервером.

Однако, если это первоначальное взаимодействие не является проблемой, представляется безопасным использование относительных путей для создания файлов сокетов, что позволяет избежать проблем с длиной пути, когда местоположение файла сокета напрямую не контролируется процессом сервера.

WhiteWinterWolf
источник