10. Сетевые приложения и службы

В этой главе рассмотрены основы сетевых приложений — клиентов и серверов, работающих в пространстве пользователя, которое располагается на прикладном уровне. Так как этот уровень находится на самом верху стека, ближе всего к конечным пользователям, материал данной главы более доступен, по сравнению с главой 9. Действительно, вы взаимодействуете с такими клиентскими сетевыми приложениями, как браузеры и почтовые клиенты, каждый день.

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

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


10.1. Основные понятия о службах

Службы TCP являются одними из самых простых для понимания, поскольку они построены на несложных, непрерывных двухсторонних потоках данных. Вероятно, лучший способ увидеть, как они работают, — «пообщаться» с веб-сервером напрямую через TCP-порт 80 и получить представление о том, как данные перемещаются через это соединение. Запустите, например, такую команду для подключения к веб-серверу:

$ telnet www.wikipedia.org 80

Вы должны увидеть в ответ нечто подобное:

Trying some address

Connected to www.wikipedia.org.

Escape character is '^]'.

Теперь введите:

GET / HTTP/1.0

Нажмите клавишу Enter дважды. Сервер должен отправить в виде ответа некоторое количество HTML-текста, а затем разорвать соединение.

Это упражнение говорит нам о том, что:

• на удаленном хосте есть процесс веб-сервера, прослушивающий TCP-порт 80;

• клиентом, который инициировал соединение, являлась команда telnet.


примечание

Команда telnet изначально была предназначена для осуществления входа на удаленные хосты. Хотя вход на удаленный сервер с помощью команды telnet без использования технологии Kerberos совершенно не защищен (как вы увидите далее), клиент telnet может быть полезен для отладки удаленных служб. Команда telnet не работает с протоколом UDP или любым транспортным уровнем, отличным от TCP. Если вы ищете сетевой клиент общего назначения, попробуйте команду netcat, описанную в подразделе 10.5.3.

В приведенном выше примере вы вручную выполнили взаимодействие с веб-сервером в сети с помощью команды telnet, использовав протокол HTTP (Hypertext Transfer Protocol, протокол передачи гипертекста) прикладного уровня. Хотя в обычных условиях вы воспользовались бы браузером для установления подобного соединения, немного отойдем от команды telnet и применим команду, которая знает, как «говорить» с прикладным уровнем HTTP. Мы используем утилиту curl со специальным параметром, чтобы записать подробности ее взаимодействия:

$ curl — trace-ascii trace_file http://www.wikipedia.org/


примечание

В вашей версии ОС может не оказаться встроенной утилиты curl, но, если она понадобится, ее установка не должна вызвать трудностей.

Вы получите обширный отчет в формате HTML. Проигнорируйте его (или перенаправьте в устройство /dev/null) и вместо этого посмотрите только что созданный файл trace_file. При условии, что соединение оказалось успешным, первая часть этого файла, в том месте, где команда curl пытается установить TCP-соединение с сервером, должна выглядеть так:

== Info: About to connect() to www.wikipedia.org port 80 (#0)

== Info: Trying 10.80.154.224… == Info: connected

Все, что вы видели до сих пор, происходит на транспортном уровне или под ним. Однако, если это соединение оказывается успешным, команда curl пытается отправить запрос («заголовок»); именно в этот момент в дело вступает прикладной уровень:

=> Send header, 167 bytes (0xa7)

0000: GET / HTTP/1.1

0010: User-Agent: curl/7.22.0 (i686-pc-linux-gnu) libcurl/7.22.0 OpenS

0050: SL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3

007f: Host: www.wikipedia.org

0098: Accept: */*

00a5:

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

Видно, что команда curl начинает работу с отправки запроса GET серверу (как вы это делали с помощью команды telnet), за которым следует дополнительная информация для сервера и пустая строка. Далее сервер отправляет ответ, первый с собственным заголовком, который выделен здесь жирным шрифтом:

<= Recv header, 17 bytes (0x11)

0000: HTTP/1.1 200 OK

<= Recv header, 16 bytes (0x10)

0000: Server: Apache

<= Recv header, 42 bytes (0x2a)

0000: X-Powered-By: PHP/5.3.10-1ubuntu3.9+wmf1

snip

Во многом подобно предыдущему выводу, здесь строки <= являются отладочными, а числа 0000:, с которых они начинаются, сообщают вам смещения.

Заголовок в ответе сервера может оказаться достаточно длинным, но в определенный момент сервер переходит от передачи заголовков к отправке запрашиваемого документа, например, так:

<= Recv header, 55 bytes (0x37)

0000: X–Cache: cp1055 hit (16), cp1054 frontend hit (22384)

<= Recv header, 2 bytes (0x2)

0000:

<= Recv data, 877 bytes (0x36d)

0000: 008000

0008: ...

snip

Этот вывод иллюстрирует также важное свойство прикладного уровня. Даже если отладочный вывод содержит Recv header и Recv data, подразумевая за ними два различных типа сообщений от сервера, нет никаких различий ни в том, как команда curl общается с операционной системой для извлечения этих сообщений, ни в том, как операционная система обращается с ними, ни в том, как сеть обрабатывает лежащие в их основе пакеты. Различие содержится полностью внутри приложения curl в пространстве пользователя. Команда curl знает о том, что она получает заголовки, пока ей не встретится пустая строка (двухбайтный фрагмент в середине), которая сигнализирует об окончании HTTP-заголовков, тогда команда интерпретирует все, что последует далее, как запрашиваемый документ.

Это же верно и для сервера, отправляющего данные. При отправке ответа сервер не делает различий между заголовком и данными документа, отправленными операционной системе; различия появляются внутри серверной программы в пространстве пользователя.


10.2. Сетевые серверы

Большинство сетевых серверов подобно другим демонам системы, таким как cron, за исключением того, что они взаимодействуют с сетевыми портами. В самом деле, вспомните демон syslogd, описанный в главе 7: он принимает пакеты UDP в сетевом порте 514, когда запущен с параметром — r.

Есть несколько других распространенных сетевых серверов, которые вы можете найти в своей системе:

• httpd, apache, apache2 — веб-серверы;

• sshd — демон защищенной оболочки (см. раздел 10.3);

• postfix, qmail, sendmail — почтовые серверы;

• cupsd — сервер печати;

• nfsd, mountd — демоны сетевой файловой системы (для совместного использования файлов);

• smbd, nmbd — демоны совместного использования файлов Windows (см. главу 12);

• rpcbind — демон удаленного вызова процедуры (RPC, Remote Procedure Call) для службы зеркала портов.

Общим свойством большинства сетевых серверов является то, что они обычно действуют в виде нескольких процессов. Хотя бы один из процессов прослушивает сетевой порт, и когда поступает новое входящее соединение, прослушивающий процесс использует команду fork(), чтобы создать новый дочерний процесс, который становится ответственным за новое соединение. Процесс-потомок, или исполнитель, завершает работу при закрытии соединения. Тем временем исходный процесс продолжает прослушивание сетевого порта. Этот процесс позволяет серверу с легкостью справляться с множеством подключений, не создавая сложностей.

Однако имеются некоторые исключения из этой модели. Вызов команды fork() добавляет системе дополнительную работу. Для сравнения: такие высокопроизводительные TCP-серверы, как веб-сервер Apache, могут во время запуска создать несколько процессов-исполнителей, чтобы они всегда были наготове для обработки соединений. Серверы, которые принимают UDP-пакеты, просто получают данные и реагируют на них. У них нет соединений, которые надо прослушивать.


10.3. Защищенная оболочка (SSH)

Каждый сервер работает по-своему. Подробно рассмотрим автономный сервер SSH. Одним из самых распространенных сетевых сервисных приложений является защищенная оболочка (SSH) — стандарт де-факто для удаленного доступа к компьютерам с Unix. Настроенная оболочка SSH дает возможность защищенного входа в оболочку, удаленного исполнения команд, простого совместного использования файлов, а также позволяет заменить старые, незащищенные системы удаленного доступа telnet и rlogin на криптографические системы с открытым ключом для аутентификации и упрощенными шифрами для сеансовых данных. Большинство поставщиков интернет-услуг и облачных сервисов требуют наличия оболочки SSH для доступа к своим сервисам, а многие сетевые устройства на основе Linux (например, устройства сетевого хранения данных) также обеспечивают доступ с помощью оболочки SSH. Оболочка OpenSSH (http://www.openssh.com/) является популярной бесплатной реализацией SSH для Unix, и она присутствует практически во всех версиях Linux. Клиент оболочки OpenSSH называется ssh, а сервер — sshd. Существуют две основные версии протокола SSH: 1 и 2. Оболочка OpenSSH поддерживает обе версии, однако первая применяется редко.

Из многих полезных возможностей и функций оболочки SSH можно упомянуть следующие:

• шифрование пароля и других сеансовых данных для защиты от шпионов;

• туннелирование других сетевых соединений, включая те, которые исходят от клиентов системы X Window (подробнее об этом рассказано в главе 14);

• наличие клиентов почти для любой операционной системы;

• использование ключей для аутентификации хоста.


примечание

Туннелирование — это процесс упаковки и передачи одного сетевого подключения с помощью другого. Преимущества использования оболочки SSH для туннелирования подключений системы X Window заключаются в том, что оболочка SSH настраивает среду отображения за вас и шифрует данные внутри туннеля.

Однако у оболочки SSH есть и свои недостатки. Для начала, чтобы установить SSH-соединение, вам необходим открытый ключ удаленного хоста, а он появляется у вас не обязательно с помощью защищенного способа (хотя можно проверить его вручную, чтобы убедиться в том, что вы не подверглись взлому). Чтобы получить представление о работе различных криптографических методов, обратитесь к книге Брюса Шнайера (Bruce Schneier) Applied Cryptography: Protocols, Algorithms, and Source Code in C («Прикладная криптография: протоколы, алгоритмы и программный код на языке C»), 2-е издание (Wiley, 1996). Более подробно об оболочке SSH и работе с ней рассказано в книге Майкла У. Лукаса (Michael W. Lucas) OpenSSH, PuTTY, Tunnels and Keys («Оболочка OpenSSH, клиент PuTTY, туннели и ключи»), а также в книге Дэниела Дж. Барретта (Daniel J. Barrett), Ричарда Е. Сильвермана (Richard E. Silverman) и Роберта Дж. Бернса (Robert G. Byrnes) SSH, The Secure Shell («SSH — защищенная оболочка»), 2-е издание (O’Reilly, 2005).


10.3.1. Сервер SSHD

Для запуска сервера sshd необходим файл конфигурации, а также ключи хоста. В большинстве версий ОС файл конфигурации находится в каталоге /etc/ssh, и если вы установили пакет sshd, то вся конфигурация будет выполнена корректно за вас. Имя файла конфигурации sshd_config легко спутать с файлом установщика клиента ssh_config, поэтому будьте внимательны.

В файле sshd_config вам не придется что-либо менять, но никогда не помешает проверить его. Этот файл состоит из пар «ключевое слово — значение», как показано в приведенном фрагменте:

Port 22

#Protocol 2,1

#ListenAddress 0.0.0.0

#ListenAddress::

HostKey /etc/ssh/ssh_host_key

HostKey /etc/ssh/ssh_host_rsa_key

HostKey /etc/ssh/ssh_host_dsa_key

Строки, которые начинаются с символа #, являются комментариями, и многие из них в файле sshd_config могут указывать на значения по умолчанию. Страница руководства sshd_config(5) содержит описание всех возможных значений, наиболее важными из которых являются:

• HostKey file — использует файл file в качестве ключа хоста (о ключах хоста скоро пойдет речь);

• LogLevel level — заносит сообщения с помощью уровня level системного журнала;

• PermitRootLogin value — позволяет пользователю superuser войти в защищенную оболочку, если значение value равно yes. Чтобы предотвратить вход, установите значение no;

• SyslogFacility name — заносит сообщения с помощью устройства name системного журнала;

• X11Forwarding value — включает туннелирование клиента системы X Window, если значение value равно yes;

• XAuthLocation path — обеспечивает путь для команды xauth. Туннелирование системы X11 не будет работать без этого пути. Если команда xauth расположена не в каталоге /usr/bin, укажите для значения path полный путь к команде xauth.


Ключи хоста

У оболочки OpenSSH есть три набора ключей хоста: один для протокола версии 1 и два для протокола 2-й версии. В каждом наборе присутствует открытый ключ (файл с расширением. pub) и секретный ключ (файл без расширения). Никому не показывайте секретный ключ, даже в собственной системе, поскольку при этом вы подвергаетесь риску вторжения злоумышленников.

В оболочке SSH версии 1 есть только ключи RSA, а в версии 2 есть ключи RSA и DSA. RSA и DSA являются алгоритмами шифрования открытого ключа. Имена файлов ключей приведены в табл. 10.1.


Таблица 10.1. Файлы ключей оболочки OpenSSH

Имя файла

Тип ключа

ssh_host_rsa_key

Секретный ключ RSA (версия 2)

ssh_host_rsa_key.pub

Открытый ключ RSA (версия 2)

ssh_host_dsa_key

Секретный ключ DSA (версия 2)

ssh_host_dsa_key.pub

Открытый ключ DSA (версия 2)

ssh_host_key

Секретный ключ RSA (версия 1)

ssh_host_key.pub

Открытый ключ RSA (версия 1)

Обычно вам не понадобится создавать ключи, поскольку за вас это выполнит команда из оболочки OpenSSH или из вашей версии ОС, но вам все же следует знать о том, как создавать ключи, если вы планируете использовать команды, подобные ssh-agent. Чтобы создать ключи для протокола SSH версии 2, используйте команду ssh-keygen, которая включена в оболочку OpenSSH:

# ssh-keygen — t rsa — N '' — f /etc/ssh/ssh_host_rsa_key

# ssh-keygen — t dsa — N '' — f /etc/ssh/ssh_host_dsa_key

Для версии 1 воспользуйтесь таким вариантом:

# ssh-keygen — t rsa1 — N '' — f /etc/ssh/ssh_host_key

Сервер SSH и клиенты применяют также файл ключей ssh_known_hosts, который содержит открытые ключи от других хостов. Если вы намерены использовать аутентификацию на основе хостов, файл ssh_known_hosts на сервере должен содержать открытые ключи хостов для всех надежных клиентов. Знание о файлах ключей пригодится, когда вы приступите к замене компьютера. При настройке нового компьютера с нуля можно импортировать файлы ключей со старого компьютера, чтобы у пользователей не возникло несоответствие ключей при подключении к новому компьютеру.


Запуск сервера SSH

Хотя в большинстве версий ОС присутствует оболочка SSH, сервер sshd обычно не запускается по умолчанию. В Ubuntu и Debian при установке пакета SSH-сервера создаются ключи, запускается сервер и заносится информация о запуске в конфигурацию загрузки системы. В Fedora сервер sshd установлен по умолчанию, но отключен. Чтобы запустить сервер sshd при загрузке системы, воспользуйтесь командой chkconfig таким образом (при этом сервер не будет запущен сразу же; для его запуска используйте команду service sshd start):

# chkconfig sshd on

В Fedora при первом запуске сервера sshd обычно создаются все отсутствующие файлы хост-ключей.

Если у вас еще не установлена поддержка системы init, то при запуске команды sshd с корневыми правами запускается сервер и во время запуска сервер sshd записывает свой идентификатор PID в файл /var/run/sshd.pid.

Можно также запустить сервер sshd в качестве модуля сокета в версии systemd или с помощью команды inetd, но это, как правило, не очень корректно, поскольку серверу иногда требуется создавать файлы ключей, а на это требуется довольно много времени.


10.3.2. Клиент SSH

Чтобы подключиться к удаленному хосту, запустите команду:

$ ssh remote_username@host

Можно опустить параметр remote_username@, если ваше локальное имя пользователя такое же, как и для хоста. Команду ssh можно также встраивать в «конвейер», как показано в приведенном ниже примере, в котором каталог dir копируется на другой хост:

$ tar zcvf—dir | ssh remote_host tar zxvf -

Файл ssh_config глобальной конфигурации клиента SSH должен располагаться в каталоге /etc/ssh вместе с вашим файлом sshd_config. Как и в файле конфигурации сервера, файл конфигурации клиента содержит пары «ключ — значение», но вам не следует их изменять.

Наиболее часто проблемы при использовании клиентов SSH возникают, если открытый ключ в локальных файлах ssh_known_hosts или. ssh/known_hosts не совпадает с ключом на удаленном хосте. Неправильные ключи могут вызвать ошибку или появление подобного предупреждения:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!

Someone could be eavesdropping on you right now (man-in-the-middle attack)!

It is also possible that the RSA host key has just been changed.

The fingerprint for the RSA key sent by the remote host is

38:c2:f6:0d:0d:49:d4:05:55:68:54:2a:2f:83:06:11.

Please contact your system administrator.

Add correct host key in /home/user/.ssh/known_hosts to get rid of this

message.

Offending key in /home/user/.ssh/known_hosts:12

RSA host key for host has changed and you have requested

strict checking.

Host key verification failed.

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

При отсутствии каких-либо подозрений просто удалите ошибочную строку или замените ее правильным открытым ключом.


Клиенты передачи файлов в оболочке SSH

Оболочка OpenSSH содержит команды для передачи файлов, scp и sftp, которые призваны заменить старые, незащищенные команды rcp и ftp.

Команду scp можно использовать для передачи файлов между удаленным компьютером и вашим или от одного хоста к другому. Она работает подобно команде cp. Приведем несколько примеров:

$ scp user@host: file.

$ scp file user@host: dir

$ scp user1@host1:file user2@host2:dir

Команда sftp работает подобно клиенту ftp из командной строки, используя команды get и put. На удаленном хосте должна быть установлена команда sftp-server, наличие которой можно ожидать, если удаленный хост также применяет оболочку OpenSSH.


примечание

Если вам необходимо больше функций и гибкости, чем предлагают команды scp и sftp (например, если вы часто передаете большие числа или файлы), обратите внимание на команду rsync, о которой рассказано в главе 12.


Клиенты SSH для платформ, отличных от Unix

Существуют клиенты SSH для всех популярных операционных систем, как указано на веб-странице проекта OpenSSH (http://www.openssh.com/). Какой из них следует выбрать? Подойдет клиент PuTTY — базовый клиент для Windows, который содержит команду защищенного копирования файлов. Клиент MacSSH хорошо работает в Mac OS 9.x и более ранних версиях. Система Mac OS X основана на Unix и уже содержит клиент OpenSSH.


10.4. Демоны inetd и xinetd

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

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

Новая версия демона inetd под названием xinetd обеспечивает упрощенную конфигурацию и лучший контроль доступа, однако роль демона xinetd сокращается в пользу применения варианта systemd, который может обеспечить такую же функциональность с помощью модулей сокетов, как описано в подразделе 6.4.7.

Хотя демон inetd уже не используется широко, его конфигурация демонстрирует все необходимое для настройки службы. Оказывается, демон sshd может быть также вызван с помощью демона inetd, а не как автономный север, что видно из файла конфигурации /etc/inetd.conf:

ident stream tcp nowait root /usr/sbin/sshd sshd — i

Семь полей, присутствующих здесь, таковы:

имя службы — имя службы из файла /etc/services (см. подраздел 9.14.3);

тип сокета — обычно это stream для протокола TCP и dgram для протокола UDP;

протокол — транспортный протокол, обычно tcp или udp;

поведение сервера дейтаграмм — для протокола UDP это wait или nowait. Службы, которые применяют другой транспортный протокол, должны использовать вариант nowait;

пользователь — имя пользователя, который запускает службу. Добавьте. group, чтобы указать группу пользователей;

исполняемый файл — команда, которую демон inetd должен подключить к службе;

аргументы — аргументы для исполняемого файла. Первый аргумент должен быть именем команды.

Обертки TCP: tcpd, /etc/hosts.allow и /etc/hosts.deny. До того как низкоуровневые брандмауэры стали популярны, многие администраторы использовали библиотеку обертки TCP и демон, чтобы контролировать хосты при работе с сетевыми службами. В таких реализациях демон inetd запускает команду tcpd, которая сначала отыскивает входящее соединение, а также списки контроля доступа в файлах /etc/hosts.allow и /etc/hosts.deny. Команда tcpd регистрирует соединение и, если она решает, что входящее соединение в порядке, передает его окончательной команде службы. Вам может встретиться система, которая по-прежнему использует обертку TCP, но мы не будем детально рассматривать ее, поскольку она выходит из употребления.


10.5. Инструменты диагностики

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

Как отмечалось в главе 9, команда netstat является базовой сетевой службой отладки, которая может отобразить разнообразную статистику о транспортном и сетевом уровнях. В табл. 10.2 приведены некоторые полезные параметры для просмотра соединений.


Таблица 10.2. Полезные параметры команды netstat, относящиеся к отчетам о соединении

Параметр

Описание

— t

Вывести информацию о порте TCP

— u

Вывести информацию о порте UDP

— l

Вывести прослушивающие порты

— a

Вывести все активные порты

— n

Отключить поиск имен (для ускорения работы; полезно также, если не работает служба DNS)


10.5.1. Команда lsof

Из главы 8 вы узнали о том, что команда lsof способна отслеживать открытые файлы, но она может также выводить список команд, которые в данный момент используют или прослушивают порты. Чтобы увидеть полный перечень команд, применяющих или прослушивающих порты, запустите такую команду:

# lsof — i

Если ее запустить с правами обычного пользователя, она покажет только процессы этого пользователя. При запуске с корневыми правами отчет будет выглядеть подобно приведенному ниже, с различными процессами и пользователями:

COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME

rpcbind 700 root 6u IPv4 10492 0t0 UDP *:sunrpc

rpcbind 700 root 8u IPv4 10508 0t0 TCP *:sunrpc (LISTEN)

avahi-dae 872 avahi 13u IPv4 21736375 0t0 UDP *:mdns

cupsd 1010 root 9u IPv6 42321174 0t0 TCP ip6-localhost: ipp (LISTEN)

ssh 14366 juser 3u IPv4 38995911 0t0 TCP thishost.local:55457->

somehost.example.com: ssh (ESTABLISHED)

chromium- 26534 juser 8r IPv4 42525253 0t0 TCP thishost.local:41551->

anotherhost.example.com: https (ESTABLISHED)

Этот пример отчета показывает пользователей и идентификаторы процессов для команд сервера и клиента, начиная со «старомодных» служб RPC вверху и заканчивая многоадресной службой DNS, которую обеспечивает команда avahi, и даже сервером печати (cupsd), готовым к использованию протокола IPv6. Две последние записи показывают соединения клиента: SSH-соединение и защищенное веб-соединение, установленное браузером Chromium. Поскольку отчет может оказаться довольно обширным, лучше применить фильтр (как рассказано в следующем разделе).

Команда lsof похожа на команду netstat тем, что она пытается выполнить обратное разрешение каждого IP-адреса в имя хоста, и это замедляет вывод. Используйте параметр — n, чтобы отключить разрешение имен:

# lsof — n -i

Можно также установить флаг — P, чтобы отключить просмотр имен портов в файле /etc/services.


Фильтрация по протоколу и порту

Если вы ищете какой-либо конкретный порт (допустим, вам известно, что какой-то процесс использует этот порт, и вы желаете узнать, что это за процесс), примените такую команду:

# lsof — i:port

Полный синтаксис такой:

# lsof — iprotocol@host: port

Параметры protocol, @host и :port являются необязательными и будут соответствующим образом фильтровать вывод команды lsof. Как и в большинстве сетевых утилит, параметры host и port могут быть либо именами, либо числами. Например, если вы желаете увидеть лишь соединения для TCP-порта 80 (это порт протокола HTTP), используйте команду:

# lsof — iTCP:80


Фильтрация по статусу соединения

Чрезвычайно удобным фильтром команды lsof является статус соединения. Чтобы, например, отобразить только те процессы, которые прослушивают порты TCP, введите такую команду:

# lsof — iTCP — sTCP: LISTEN

Эта команда даст вам хороший обзор процессов сетевого сервера, запущенных в данный момент в системе. Однако, поскольку серверы UDP не выполняют прослушивание и не имеют соединений, вам придется использовать параметр — iUDP, чтобы увидеть запущенные клиенты наряду с серверами. Как правило, это не вызовет затруднений, так как в вашей системе будет, вероятно, немного серверов UDP.


10.5.2. Команда tcpdump

Если вам необходимо в точности узнать, что проходит через вашу сеть, команда tcpdump переводит карту сетевого интерфейса в неизбирательный режим и докладывает о каждом пакете, который перемещается по проводам. Если ввести команду tcpdump без аргументов, то в результате появится отчет, подобный приведенному, содержащий запрос ARP и веб-соединение:

# tcpdump

tcpdump: listening on eth0

20:36:25.771304 arp who-has mikado.example.com tell duplex.example.com

20:36:25.774729 arp reply mikado.example.com is-at 0:2:2d: b:ee:4e

20:36:25.774796 duplex.example.com.48455 > mikado.example.com.www: S

3200063165:3200063165(0) win 5840

(DF)

20:36:25.779283 mikado.example.com.www > duplex.example.com.48455: S

3494716463:3494716463(0) ack 3200063166 win 5792

4620[|tcp]> (DF)

20:36:25.779409 duplex.example.com.48455 > mikado.example.com.www:. ack 1 win

5840 (DF)

20:36:25.779787 duplex.example.com.48455 > mikado.example.com.www: P 1:427(426)

ack 1 win 5840 (DF)

20:36:25.784012 mikado.example.com.www > duplex.example.com.48455:. ack 427

win 6432 (DF)

20:36:25.845645 mikado.example.com.www > duplex.example.com.48455: P 1:773(772)

ack 427 win 6432 (DF)

20:36:25.845732 duplex.example.com.48455 > mikado.example.com.www:. ack 773

win 6948 (DF)

9 packets received by filter

0 packets dropped by kernel

Можно сделать этот отчет более конкретным, если добавить фильтры. Можно выполнить фильтрацию на основе хостов источника и назначения, сети, адресов Ethernet, протоколов и множества различных уровней в модели сети, а также многого другого. В число протоколов, которые распознает команда tcpdump, входят протоколы ARP, RARP, ICMP, TCP, UDP, IP, IPv6, AppleTalk и пакеты IPX. Чтобы, например, вывести с помощью команды tcpdump только пакеты TCP, запустите:

# tcpdump tcp

Чтобы увидеть веб-пакеты и пакеты UDP, введите такую команду:

# tcpdump udp or port 80


примечание

Если вам необходима тщательная проверка пакетов, попробуйте использовать альтернативу команде tcpdump с графическим интерфейсом — например, приложение Wireshark.


Примитивы

В предыдущих примерах элементы tcp, udp и port 80 называются примитивами. Самые важные примитивы приведены в табл. 10.3.


Таблица 10.3. Примитивы команды tcpdump

Примитив

Спецификация пакета

tcp

Пакеты TCP

udp

Пакеты UDP

port port

Пакеты TCP и/или UDP к порту port или от него

host host

Пакеты к хосту host или от него

net network

Пакеты к сети network или от нее


Операторы

В предыдущем примере в качестве оператора применяется слово or. Команда tcpdump может использовать несколько операторов (таких как and и!), которые можно группировать с помощью скобок. Если вы планируете какую-либо серьезную работу с командой tcpdump, обязательно прочтите страницы руководства, в особенности раздел, который описывает примитивы.


Когда не следует применять команду tcpdump

Будьте очень осторожны при использовании команды tcpdump. Отчет команды tcpdump, показанный выше в этом разделе, содержит только информацию заголовка пакетов TCP (транспортный уровень) и IP (интернет-уровень), но вы можете также вывести с помощью команды tcpdump все содержимое пакета. Хотя многие сетевые операторы позволяют с легкостью просматривать сетевые пакеты, не следует шпионить за сетями, если вы не являетесь их владельцем.


10.5.3. Команда netcat

Если вам необходимо больше гибкости, чем позволяет команда вроде telnet host port при соединении с удаленным хостом, используйте команду netcat (или nc). Эта команда может подключаться к удаленным портам TCP/UDP, определять локальный порт, прослушивать и сканировать порты, перенаправлять стандартный ввод/вывод к сетевым соединениям и от них, а также многое другое. Чтобы открыть TCP-соединение с портом с помощью команды netcat, запустите:

$ netcat host port

Команда netcat завершает работу, только если другая сторона соединения разрывает его. Это может привести к путанице, если вы перенаправляете стандартный ввод в команду netcat. Разорвать соединение в любой момент можно с помощью нажатия сочетания клавиш Ctrl+C. Если вы предпочитаете, чтобы команда завершала работу и разрывала соединение на основе стандартного потока ввода, попробуйте команду sock.

Для прослушивания конкретного порта запустите такую команду:

$ netcat — l -p port_number


10.5.4. Сканирование портов

Иногда неизвестно даже то, какие службы предлагают компьютеры вашей сети или какие IP-адреса используются. Утилита Network Mapper (Nmap) сканирует все порты компьютера или сети компьютеров в поисках открытых портов, а затем выводит список всех обнаруженных портов. Большинство версий ОС содержит пакет Nmap, который можно также получить на сайте http://www.insecure.org/. Ознакомьтесь со страницей руководства по утилите Nmap или онлайн-источниками, чтобы узнать о том, что она может делать.

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


внимание

Если кто-либо еще контролирует сеть, которую вы собираетесь просканировать с помощью команды Nmap, спросите разрешение. Администраторы сети следят за сканированием портов и, как правило, лишают доступа те компьютеры, которые пользуются этим.

Запустите команду nmap host, чтобы выполнить обобщенное сканирование портов. Например, так:

$ nmap 10.1.2.2

Starting Nmap 5.21 (http://nmap.org) at 2015-09-21 16:51 PST

Nmap scan report for 10.1.2.2

Host is up (0.00027s latency).

Not shown: 993 closed ports

PORT STATE SERVICE

22/tcp open ssh

25/tcp open smtp

80/tcp open http

111/tcp open rpcbind

8800/tcp open unknown

9000/tcp open cslistener

9090/tcp open zeus-admin

Nmap done: 1 IP address (1 host up) scanned in 0.12 seconds

Как видите, здесь открыто несколько служб, многие по умолчанию не включены в большинстве версий ОС. На самом деле единственным портом, который по умолчанию включен, является порт 111 (порт rpcbind).


10.6. Удаленный вызов процедур (RPC)

Что же это за служба rpcbind, которую вы только что видели в предыдущем разделе при сканировании? RPC означает «удаленный вызов процедур» (Remote Procedure Call). Это система, которая расположена в нижней части прикладного уровня. Она предназначена для того, чтобы программистам было легче получать доступ к сетевым приложениям, используя следующее обстоятельство: команды вызывают функции в удаленных командах (которые идентифицируются по номерам), а затем удаленные команды возвращают результат или сообщение.

В реализациях RPC использованы транспортные протоколы, такие как TCP и UDP, и для них необходима специальная посредническая служба, которая сопоставляет номера команд с портами TCP и UDP. Сервер под названием rpcbind должен быть запущен на каждом компьютере, который будет использовать службы RPC.

Чтобы узнать, какие службы RPC есть на вашем компьютере, запустите такую команду:

$ rpcinfo — p localhost

Протокол RPC является одним из тех, который просто не должен выйти из употребления. Сетевая файловая система (NFS, Network File System) и служба сетевого информирования (NIS, Network Information Service) используют протокол RPC, но они абсолютно излишни для автономных компьютеров. Однако, как только вы решите, что полностью избавились от необходимости в команде rpcbind, возникает что-либо еще, например поддержка монитора доступа к файлам (FAM, File Access Monitor) в среде GNOME.


10.7. Сетевая безопасность

Поскольку Linux является очень популярным вариантом Unix для персональных компьютеров, в особенности потому, что широко используется для веб-серверов, она притягивает внимание многих субъектов, которые пытаются проникнуть в компьютерные системы. Нами были рассмотрены брандмауэры, но на этом рассказ о безопасности не заканчивается.

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

Запускайте как можно меньше служб. Взломщики не смогут взломать службу, которой нет в вашей системе. Если вы знаете о какой-либо службе, что она не используется вами, не включайте ее только из соображений, что она может вам пригодиться «когда-нибудь потом».

Блокируйте с помощьюбрандмауэра настолько много, насколько возможно. В системах Unix есть несколько внутренних служб, о которых вы можете не догадываться (например, TCP-порт 111 для сервера RPC), и о них не следует знать никакой другой системе в мире. Может оказаться очень трудно отслеживать службы и управлять ими, если различные команды прослушивают разные порты. Чтобы не позволить взломщикам определить внутренние службы вашей системы, используйте эффективные правила для брандмауэра, а также установите брандмауэр в вашем маршрутизаторе.

Отслеживайте службы, которые выходят в Интернет. Если у вас запущен сервер SSH, Postfix или подобные им службы, обновляйте программное обеспечение и принимайте соответствующие меры защиты (см. подраздел 10.7.2).

Используйте для серверов дистрибутивы «с долгосрочной поддержкой». Группы разработчиков систем безопасности обычно вплотную работают над стабильными и поддерживаемыми релизами ПО. Релизам для разработчиков и для тестирования, таким как Debian Unstable и Fedora Rawhide, уделяется гораздо меньше внимания.

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

Не устанавливайте сомнительные двоичные пакеты. Они могут содержать вирусы-трояны.

Такова практическая сторона самозащиты. Почему это важно? Есть три основных типа сетевых атак.

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

DoS-атака (Denial-of-Service, отказ в обслуживании). В этом случае компьютеру мешают выполнять сетевые службы или принуждают к неправильной работе каким-либо другим способом, не используя какого-либо специального доступа. Такие атаки трудно предотвратить, но на них проще отреагировать.

Вредоносные программы. Пользователи Linux в основном защищены от таких вредоносных программ, как почтовые черви и вирусы, просто потому, что почтовые клиенты не настолько глупы, чтобы запускать программы, которые они обнаруживают в приложенных файлах. Однако вредоносные программы для Linux все же существуют. Избегайте загрузки и установки двоичного ПО из незнакомых онлайн-ресурсов.


10.7.1. Типичные уязвимости

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

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


примечание

Если у вас есть служба, не обладающая встроенной поддержкой шифрования, попробуйте утилиту Stunnel (http://www.stunnel.org/) — пакет шифрующей обертки, похожий на обертку TCP. Подобно команде tcpd, утилита Stunnel особенно хорошо действует для служб inetd.

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

• ftpd — по какой-то причине все FTP-серверы переполнены уязвимостями. Кроме того, большинство FTP-серверов использует пароли в виде простого текста. Если вам необходимо передавать файлы с одного компьютера на другой, попробуйте применить решение на основе SSH или сервер rsync.

• telnetd, rlogind, rexecd — все эти службы передают данные удаленного сеанса (в том числе и пароли) в виде простого текста. Избегайте их, если у вас не установлена версия с применением технологии шифрования Kerberos.

• fingerd — взломщики могут получить списки пользователей и другую информацию с помощью службы сканера отпечатков пальцев.


10.7.2. Онлайн-ресурсы, посвященные безопасности

Вот несколько хороших сайтов, посвященных вопросам безопасности:

• http://www.sans.org/ — предлагает тренинги, сервисы, бесплатное еженедельное новостное письмо с перечислением важнейших уязвимостей, примеры политик безопасности и многое другое;

• http://www.cert.org/ — здесь можно узнать о самых серьезных проблемах;

• http://www.insecure.org/ — на этом сайте можно получить утилиту Nmap и другие ссылки на различные инструменты проверки сети на устойчивость к взломам. Это сайт намного более открыт и конкретен по сравнению с другими.

Если вас заинтересовала сетевая безопасность, следует узнать все о протоколе TLS (Transport Layer Security, защита (безопасности) транспортного уровня) и о его предшественнике — протоколе SSL (Secure Socket Layer, уровень защищенных сокетов). Сетевые уровни пространства пользователя обычно добавляются к сетевым клиентам и серверам для поддержки трансакций с помощью шифрования с открытым ключом и сертификатов. Хорошим руководством послужит книга Дейви (Davie) Implementing SSL/TLS Using Cryptography and PKI («Реализация протоколов SSL/TLS с применением криптографии и инфраструктуры открытых ключей», Wiley, 2011).


10.8. Заглядывая вперед

Если вам интересно попрактиковаться с какими-либо сложными сетевыми серверами, используйте веб-сервер Apache и почтовый сервер Postfix. В частности, сервер Apache легко установить, и большинство версий ОС содержит пакет поддержки. Если ваш компьютер расположен за брандмауэром или маршрутизатором с функцией NAT, можете экспериментировать с конфигурацией этого сервера сколько пожелаете, не беспокоясь о безопасности.

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


10.9. Сокеты: как процессы взаимодействуют с сетью

Сейчас мы «включим другую передачу» и посмотрим, как процессы выполняют работу по чтению данных из сети и записи данных в сеть. Достаточно просто выполняется чтение/запись для сетевых соединений, уже настроенных: для этого потребуются некоторые системные вызовы, о которых вы можете прочитать на страницах руководства recv(2) и send(2). С точки зрения процесса, возможно, самое важное — узнать, как ссылаться на сеть при использовании таких системных вызовов. В системах Unix процесс задействует сокет, чтобы идентифицировать, когда и как он «общается» с сетью. Сокеты являются интерфейсом, который процессы применяют для доступа к сети через ядро, они представляют собой границу между пространством пользователя и пространством ядра. Сокеты также часто используются для межпроцессного взаимодействия (IPC, Interprocess Communication).

Существуют разные типы сокетов, так как процессам необходимо получать доступ к сети по-разному. Например, TCP-соединения представлены сокетами потоков (SOCK_STREAM, с точки зрения программиста), а UDP-соединения — сокетами дейтаграмм (SOCK_DGRAM).

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

Схема на рис. 10.1 показывает, сколько серверов обслуживают соединения от входящих сокетов потоков. Обратите внимание на то, что этот тип серверов затрагивает два типа сокетов: сокет прослушивания и сокет для чтения и записи. Основной процесс использует сокет прослушивания для поиска подключений от сети. Когда возникает новое подключение, основной процесс применяет системный вызов accept(), чтобы принять подключение, создав при этом сокет чтения/записи, предназначенный для этого соединения. После этого основной процесс использует команду fork(), чтобы создать новый дочерний процесс для работы с новым соединением. Наконец, исходный сокет остается в роли прослушивателя и продолжает поиск новых подключений от имени основного процесса.

Когда процесс настроит сокет определенного типа, он может взаимодействовать с ним подходящим для этого сокета способом. Именно это делает сокеты гибкими: если вам необходимо изменить лежащий в основе транспортный уровень, вам не потребуется переписывать все части кода, которые отвечают за отправку и получение данных; вам понадобится лишь изменить код инициализации.

Если вы программист и хотели бы изучить, как использовать интерфейс сокетов, то классическим руководством является 3-е издание книги У. Ричарда Стефенса (W. Richard Stephens), Билла Феннера (Bill Fenner) и Эндрю М. Рудоффа (Andrew M. Rudoff) Unix Network Programming, Volume 1 («Программирование для сетей Unix. Том 1», Addison-Wesley Professional, 2003). Во втором томе рассмотрено также межпроцессное взаимодействие.

Рис. 10.1. Один из методов принятия и обработки входящих соединений


10.10. Сокеты домена Unix

Приложения, которые используют сетевые средства, не обязаны задействовать два отдельных хоста. Многие приложения разработаны как механизмы «клиент — сервер» или «узел — узел», в которых процессы, запущенные на одном и том же компьютере, используют межпроцессное взаимодействие (IPC), чтобы выяснить, какую работу необходимо выполнить и кто этим займется. Вспомните, например, о том, что демоны вроде systemd и NetworkManager используют шину D-Bus для отслеживания системных событий и реагирования на них.

Процессы могут использовать для взаимодействия обычную IP-связь через локальный хост сети (127.0.0.1), но вместо этого, как правило, применяется специальный тип сокета, о котором мы вкратце упомянули в главе 3, — сокет домена Unix. Когда процесс подключается к сокету домена Unix, он ведет себя почти так же, как и сетевой сокет: может прослушивать и принимать подключения к сокету, и вы можете даже выбирать между различными типами сокетов, чтобы он работал как сокет TCP или UDP.


примечание

Важно помнить о том, что сокет домена Unix не является сетевым сокетом и за ним не расположено никакой сети. Для его использования даже нет необходимости настраивать сеть. К тому же сокеты домена Unix не должны быть привязаны к файлам сокетов. Процесс может создать безымянный сокет домена Unix и сообщить его адрес другому процессу.


10.10.1. Преимущества для разработчиков

Разработчикам нравятся сокеты домена Unix для межпроцессного взаимодействия. На это есть две причины. Во-первых, эти сокеты дают возможность использовать специальные файлы сокетов в файловой системе для контроля доступа, чтобы любой процесс, у которого нет доступа к файлу сокета, не смог применить сокет. Поскольку здесь отсутствует взаимодействие с сетью, такой вариант проще и дает меньше поводов для стандартных вторжений в сеть. Например, в каталоге /var/run/dbus обычно можно обнаружить такой файл сокета для шины D-Bus:

$ ls — l /var/run/dbus/system_bus_socket

srwxrwxrwx 1 root root 0 Nov 9 08:52 /var/run/dbus/system_bus_socket

Во-вторых, поскольку ядру Linux при работе с сокетами домена Unix не приходится проходить через множество уровней сетевой подсистемы, производительность при этом улучшается.

Написание программного кода для сокетов домена Unix не сильно отличается от поддержки обычных сетевых сокетов. Поскольку преимущества от этого могут быть существенными, некоторые сетевые серверы осуществляют взаимодействие как по сети, так и через сокеты домена Unix. Например, сервер mysqld базы данных MySQL способен принимать клиентские соединения от удаленных хостов, и он же обычно предлагает сокет домена Unix в файле /var/run/mysqld/mysqld.sock.


10.10.2. Просмотр списка сокетов домена Unix

Можно просмотреть список сокетов домена Unix, которые в данный момент использованы в системе, с помощью команды lsof — U:

# lsof — U

COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME

mysqld 19701 mysql 12u unix 0xe4defcc0 0t0 35201227 /var/run/mysqld/

mysqld.sock

chromium- 26534 juser 5u unix 0xeeac9b00 0t0 42445141 socket

tlsmgr 30480 postfix 5u unix 0xc3384240 0t0 17009106 socket

tlsmgr 30480 postfix 6u unix 0xe20161c0 0t0 10965 private/tlsmgr

snip

Этот перечень будет довольно длинным, так как многие современные приложения широко используют безымянные сокеты. Их можно узнать по идентификатору socket в столбце NAME такого отчета.

Загрузка...