Глава 22. Супер Сервер Интернет inetd

Глава 22. Супер Сервер Интернет inetd

Русский перевод: Александр Журавлев

"Супер сервер Интернет" или inetd(8) доступен на всех Unix–подобных системах, предоставляя множество из имеющихся базовых сервисов. Данная глава описывает взаимосвязь между демоном и несколькими конфигурационными файлами из директории /etc/.

22.1. Обзор

В данном документе мы взглянем на простое определение inetd(8), на то, как работают несколько файлов, относящихся к inetd(8) (хотя это не означает, что они не относятся к другому программному обеспечению), то как добавлять сервис в inetd(8) и некоторые предложения по использованию inetd(8) для определенного сервиса и о том, когда для сервиса лучшим выбором будет работа вне inetd(8).

22.2. Что такое inetd?

В традиционном для Unix сценарии один процесс сервера (демон) наблюдает за соединениями на определенном порту и обрабатывает входящие запросы. В данном случае, если машина предлагает множество сервисов, понадобился бы запуск многих процессов демонов, большей частью находящихся в состоянии ожидания, но все же растрачивая ресурсы, например, память. Супер сервер Интернет, inetd – это подход к решению данной проблемы. Он ожидает соединения на нескольких портах и, когда получает запрос на обслуживание, определяет приложение, которое должно обслужить данный запрос, и запускает экземпляр этой программы.

Ниже приведена очень простая диаграмма, демонстрирующая inetd(8):

  pop3  ------  |
                |
  ftpd -------  | INETD | ---- Интернет / ДМЗ / Свитч / Что-либо еще . . .
                |
 cvsupserver -  |

На вышеприведенной диаграмме вы можете лицезреть главную идею. Процесс inetd(8) получает запрос и затем запускает соответсвующий серверный процесс. То, что делает inetd(8) – это программное мультиплексирование. Одно важное замечание касающееся безопасности: на множестве других UNIX–подобных системах пакет называемый tcpwrappers используется для улучшения безопасности inetd(8). В NetBSD функциональность tcpwrappers встроена в inetd(8) за счет использования библиотеки libwrap.

22.3. Конфигурация inetd – /etc/inetd.conf

Работа inetd(8) контроллируется своим собственным файлом, к удивлению называемому /etc/inetd.conf, для информации смотрите inetd.conf(5). В основном, файл inetd.conf обеспечивает включение и отображение имен сервисов, которые системный администратор желает мультиплексировать, используя inetd(8), отражая то, какое приложение должно быть запущено и на каком порту оно будет ожидать входящие соединения.

Файл inetd.conf(5) является текстовым (ascii) файлом, содержащим описание одного сервиса на каждой строке файла, которая, в свою очередь, разделяется на несколько полей. Размещение основных полей в строке следующее:

имя–сервиса тип–сокета протокол wait/nowait пользователь:группа программа–сервер аргументы
Имя–сервиса:

Имя сервиса отражает номер порта, на котором inetd(8) должен ожидать входящие соединения. Это либо десятичное число, либо имя сервиса приведенное в файле /etc/services.

Тип–сокета:

Тип коммуникационного сокета. К различным типам сокета относятся: "stream" для потоковых сокетов, "dgram" для UDP сервисов, "raw" для бинарных сокетов, "rdm" для сообщений с гарантированной доставкой и "seqpacket" для сокетов упорядоченных пакетов. Наиболее распространенные типы сокетов – "stream" и "dgram".

Протокол

Используемый протокол. В основном это "tcp", "tcp6", "udp" и "udp6" для потоко–ориентированных сервисов использующих Протокол котроля передачи данных (Transmission Control Protocol) или Притокол пользовательских датаграмм (User Datagram Protocol) для датаграммно–ориентированных сервисов. Стоит упомянуть, что "tcp" и "udp" означают, что они используют протокол по умолчанию (в настоящий момент - Протокол IP версии 4), запись "tcp4" означает, что данный сервис обслуживает соединения используя только протокол IPV4, а "tcp6" и "udp6" – соединения используя только протокол IPV6. В дополнение к перечисленным, протоколы основанные на удаленном вызове процедур (RPC) могут быть обозначены как "rpc/tcp" или "rpc/udp".

wait/nowait

Значение данного поля говорит inetd(8) должен ли он ждать возврата из программы сервера, или немедленно возвращаться к обработке новых соединений. Многие соединения к серверам требуют ответа после того, как передача данных завершена, когда другие могут продолжать передачу данных непрерывно, в последнем cлучае упоминается ситуация типичная для "nowait", а более раннем случае – "wait". В большинстве случаев данное значение соответствует типу сокета, к примеру, потоковым соединениям будет соответствовать значение "nowait" данного поля.

имя пользователя[:группа]

Данноe поле указывает имя пользователя и, опционaльно, имя группы, от имени которых должен стартовать серверный процесс запущенный из inetd(8).

программа–сервер

В данном поле указывается полный путь к программе, которая должна быть запущена.

список–аргументов

Данное поле содержит список аргументов запускаемой программы (argv[]), включая имя программы и дополнительные аргументы программы, которые системному администратору возможно понадобиться указать.

И это еще не все, что можно указать и есть другие вещи, которые может сделать системный администратор с некоторыми из полей. Ниже приведена примерная строка из файла inetd.conf:

ftp  stream tcp nowait root /usr/libexec/ftpd ftpd -ll

Начиная слева, имя–сервиса – "ftp", тип–сокета – "stream", протокол – "tcp", inetd(8) не будет ожидать завершения процесса сервера ("nowait"), процесс будет выполняться от имени пользователя "root", путь к программе /usr/libexec/ftpd и имя программы с аргументами – "ftpd -ll". Заметьте, что в последнем поле имя программы отличается от имени–сервиса.

22.4. Сервисы – /etc/services

Следующий файл, который необходимо рассмотреть – это файл, хранящий базу данных о именах сервисов, которая может быть найдена в файле /etc/services. Этот файл в основном содержит информацию об отображении имен сервисов на соответствующие номера портов. Файл имеет следущий формат:

имя–сервиса номер–порта/имя–протокола [псевдонимы] 

"имя–сервиса" соответствует имени сервиса, "номер–порта" – номер порта, присвоенный данному сервису, "имя–протокола" – это либо "tcp", либо "udp". И если нужны псеводнимы для порта, они могут быть добавлены в поле "псеводнимы" будучи разделенными пробельными символами. После символа "#" можно указать комментарии.

К примеру, давайте взглянем на запись соответствующую сервису "ssh":

 ssh    22/tcp   # Secure Shell
ssh    22/udp

Как мы можем видеть, начиная слева, имя сервиса – "ssh", номер порта – 22, указаны оба протокола ("tcp" и "udp"). Заметьте, что для каждого протокола используется отдельная запись (даже для того же номера порта).

22.5. Протоколы – /etc/protocols

Еще один файл, который проcсматривается inetd(8) это файл /etc/protocols. Данный файл содержит информацию имеющую отношение к интернет протоколам DARPA. Формат файла следующий:

имя–протокола число [псеводнимы]

Где "имя–протокола" описывает тип полезной нагрузки IP пакета, к примеру, "tcp" или "udp". "число" - официальный номер порта, назначенный IANA, и дополнительные псевдонимы протокола могут быть указаны после этого поля.

К примеру, давайте взглянем на седьмую запись базы протоколов /etc/protocols:

tcp  6  TCP    # transmission control protocol

Начиная слева, мы видим, что имя протокола – "tcp", номер протокола – "6" и единственный приведенный псевдоним протокола – "TCP" принадлежат протоколу контроля передачи данных (Transmission Control Protocol), что отражено в комментарии на данной строке.

22.6. Вызов удаленных процедур (RPC) – /etc/rpc

База данных номеров программ rpc, используемых сервисами, имеющими типом протокола "rpc" в inetd.conf(5), хранится в файле /etc/rpc и содержит отображение имен программ на их номера. Файл имеет следующий формат:

имя–сервера номер–программы псеводнимы

К примеру, ниже приведена запись для nfs:

nfs    100003 nfsprog

22.7. Разрешение и запрещение доступа с определенных хостов – /etc/hosts.{allow,deny}

Как было указано выше, inetd(8) NetBSD имеет пакет tcpwrappers встроенным в него за счет использования библиотеки libwrap. Таким образом, inetd(8) позволяет разрешать и отказывать в доступе к каждому сервису более детальным образом, чем простое разрешение доступа к сервису всем, или не предоставление сервиса вообще. Контроль доступа определяется в следующих фалах /etc/hosts.allow и /etc/hosts.deny, смотрите страницу руководства hosts_access(5).

Каждый из этих файлов содержит несколько строк, описывающих ограничения доступа для определенного сервера. Доступ предоставляется, если соответствующие права предоставлены в /etc/hosts.allow. Если сервис не указан в /etc/hosts.allow, но указан в /etc/hosts.deny, доступ к нему запрещен. Если сервис не указан ни в одном из файлов, доступ к нему разрешен, обеспечивая, таким образом, стандартное поведение inetd(8).

Каждая строка файлов /etc/hosts.allow и /etc/hosts.deny содержит обращение к сервису либо по его имени (как оно указано в поле argv[0] файла /etc/inetd.conf, к примеру "ftpd" вместо "ftp"), либо специальное имя сервиса – "ALL", которое, очевидно, применимо ко всем сервисам. За именем сервиса, отделенного двоеточием, следуют разделенные запятыми правила ограничения доступа, которые могут быть именем хоста, доменом, одним интернет адресом, либо целой подсетью адресов, либо другим ограничением. Вы можете обратиться к странице руководства hosts_access(5) за более детальным описанием.

Примерная конфигурация, которая большей частью разрешает доступ, но закрывает доступ к сервисам для определенного хоста и для всех машин из определенного домена, будет выглядеть следующим образом:

# /etc/hostname.deny:
ALL: some.host.name, .some.domain

Другой пример, который будет полностью закрытым, запрещая доступ всем за исключением нескольких машин, потребует записей в файлах /etc/hosts.allow и /etc/hosts.deny. Запись для /etc/hosts.deny будет следующей:

# /etc/hosts.deny
ALL: ALL 

Запись разрешающая доступ нескольким хостам будет помещена в /etc/hosts.allow:

# /etc/hosts.allow
ALL: friend.host.domain otherfriend.otherhost.otherdomain

22.8. Добавление сервиса

Часто системные администраторы могут обнаружить, что им необходимо добавить в свою систему сервис, записи для которого еще нет в inetd(8), или захотят переместить в него сервис, потому что он не потребляет большого объема трафика. Обычно это довольно легко сделать, как пример мы рассмотрим добавление версии POP3 сервиса в NetBSD.

В данном случае мы скачали и установили пакет "cucipop", который может быть найден в pkgsrc/mail/cucipop. Данный сервер логок в использовании, единственной странностью является различное расположение путей. Мы знаем, что протокол POP3 является потоко–ориентированным с типом соединения "nowait". Мы допускаем запуск сервиса от имени пользователя "root", единственным отличием является расположение программы и ее имя.

Таким образом, первая половина новой записи файла /etc/inetd.conf будет выглядеть так:

pop3 stream tcp  nowait root

После установки, система установки пакетов разместила cucipop в /usr/pkg/sbin/cucipop. Следовательно, вместе со следующим полем мы имеем:

pop3 stream tcp  nowait root /usr/pkg/sbin/cucipop

Наконец, мы хотим использовать формат почтового ящика Беркли, следовательно программа должны быть запущена с параметром -Y. Это приводжит к тому, вся запись в целом будет выглядеть так:

pop3 stream tcp  nowait root /usr/pkg/sbin/cucipop cucipop -Y

Мы добавили сервис с именем "pop3" в /etc/inetd.conf. Следующим пунктом, который необходимо осуществить, является проверка того, может ли система отобразить имя сервиса на номер порта в /etc/services:

# grep ^pop3 /etc/services
pop3   110/tcp   # POP version 3
pop3   110/udp
pop3s   995/tcp     # pop3 protocol over TLS/SSL (was spop3)
pop3s   995/udp     # pop3 protocol over TLS/SSL (was spop3)

Для нас представляют интерес записи "pop3", то есть они уже содержатся в файле /etc/services поставляемом с NetBSD.

Теперь для того, чтобы заставить inetd(8) использовать новую запись, нам просто нужно перезапустить его, используя скрипт инициализации системы:

# sh /etc/rc.d/inetd restart

Это все. В большинстве случаев, программное обеспечение, которое вы будете использовать, содержит документацию, указывающую соответсвующую запись для inetd(8), однако если оно не содержит таковой, то иногда помогает попытка найти запись для программы аналогичной добавляемой. Классическим примером является MUD (Multy User Dangeon) сервер, который содержит встроенный телнет сервис. В таком случае вы просто можете использовать уже существующую запись для телнет сервиса и изменить только необходимые части.

22.9. Когда использовать или не использовать inetd

Обычно решение о том, добавить ли сервис или удалить из inetd(8) основывается на загрузке сервера. К примеру, на большинстве систем сервер телнет не требует такого значительного количества входящих соединений, как, скажем, почтовый сервер. В большинстве случаев администратор должен выяснить, необходимо ли удаление сервиса или нет.

Хорошим примером, который мне довелось увидеть, являются почтовые сервисы, такие как SMTP и POP. Я установил почтовый сервер, в котором pop3 сервис обслуживался inetd(8), а exim выполнялся как отдельный процесс. Я ошибочно предполагал, что все будет работать замечательно, потому что системой пользовалось малое количество пользователей - я сам и диагностический пользователь. К тому же, сервер использовался как запасной почтовый сервер и пересcылщик почты в случае, если другой высоко загруженный сервер выйдет из строя. Когда же я провел несколько тестов, я обнаружил значительную задержку при удаленном заборе почты с pop сервера. Это было связано с тем, что я непрерывно забирал с сервера почту, и с тем, что диагностический пользователь постоянно высылал диагностические сообщения туда и обратно. В конце концов, мне пришлось удалить pop3 сервис из inetd(8).

На самом деле, причина удаления сервиса довольно интереcна. Когда какой-либо сервис начинает интенсивно использоваться, конечно же, это приводит к высокой нагрузке системы. В случае сервиса, который выполняется в пределах inetd(8) мета демона, эффекты от высоко загруженного сервиса могут повредить другим сервисам, которые также используют inetd(8). Если мультиплексор получает слишком большое количество соединений к одному определенному сервису, это начинает сказываться на производительности других сервисов, использующих inetd(8). Решением в ситуации подобной описанной выше является настройка того, чтобы сервис причиняющий неудобства выполнялся вне пределов inetd(8), что приведет к увеличению времени отклика самого сервиса и inetd(8).

22.10. Другие ресурсы

Ниже приведена информация для дополнительного ознакомления и о темах, освещенных в данном документе.

Страницы руководства NetBSD:

Дополнительные ссылки:

Обновлено: 16.03.2015