№12(13) декабрь 2003 подписной индекс 81655 журнал для cистемных администраторов, вебмастеров и программистов
Практические советы по восстановлению системы Крепость для пингвина: Bastille Linux Вторая жизнь модемов Осваиваем Nagios LTSP Инвентаризация в сети Конвертирование из Excel в HTML
№12(13) декабрь 2003
Профсоюз IT-специалистов
оглавление КАЛЕНДАРЬ СОБЫТИЙ
HARDWARE
SYSM.02
Вторая жизнь модемов
Запланируйте участие: второй Семинар системных администраторов и инженеров.
2
Профсоюз IT-специалистов IT-специалисты России, соединяйтесь! В декабре состоится учредительное собрание Межрегионального Профессионального союза специалистов в области информационных технологий.
Способы использования модемов, внутреннее устройство постоянной памяти, программирование микросхем flash-памяти с помощью модема Acorp, замена версий в модемах ZyXEL 1496, подключение 3-х модемов, развод используемых прерываний и настройка в ОС Linux. Павел Закляков amdk7@mail.ru 62
3
WEB
ПРОГРАММИРОВАНИЕ Практические советы по восстановлению системы в боевых условиях Возможные причины нестабильной работы и сбоев системы и рекомендации по их устранению. Крис Касперски kk@sendmail.ru 6
Конвертирование из Excel в HTML: корректно, качественно, просто Идеи для корректного конвертирования документов из формата xls в формат HTML с учетом форматирования исходных документов. Алексей Мичурин 76 alexey@office-a.mtu-net.ru
АДМИНИСТРИРОВАНИЕ
ОБРАЗОВАНИЕ
Решение задач инвентаризации в сети
LTSP – вторая жизнь старых компьютеров
Инвентаризация аппаратного обеспечения рабочих станций в сети, построенной на основе Windows 2000/XP. Иван Коробко ikorobko@prosv.ru 26
Крепость для пингвина Обзор и установка Bastille Linux – утилиты, позволяющей улучшить и укрепить безопасность Linux-системы. Сергей Яремчук grinder@ua.fm 40
Использование инструмента LTSP (Linux Terminal Server Proekt) для решения вопроса загрузки бездисковых терминалов. Сергей Яремчук grinder@ua.fm 84
Содержание журнала за 2003 год
92
Учет работы Dialup-пользователей в системе FreeBSD Общие принципы решения задачи. Сергей Супрунов amsand@rambler.ru
44
Осваиваем Nagios Русификация веб-интерфейса, описание процедуры инсталляции дополнительного программного обеспечения, необходимого для работы с плоской и трехмерной картами сети, создание иконок хостов и сервисов, настройка иерархии хостов и многое другое. Андрей Бешков tigrisha@sysadmins.ru 48
№12(13), декабрь 2003
1
календарь событий
SYSM.02 20 декабря 2003 года, г. Москва Портал SysAdmins.RU объявляет о проведении второго Семинара системных администраторов и инженеров и приглашает специалистов принять участие в мероприятии, которое обещает быть плодотворным и информативным. Первая часть Семинара будет посвящена обсуждению проблем информационной безопасности, вопросам управления информационными системами, планированию карьеры. Далее состоится учредительное собрание «Профсоюза специалистов в области информационных технологий», будут проведены выборы Правления профсоюза и выработана программа действий профсоюза на 2004 год. Опыт проведения первого Семинара показал, что данное мероприятие вызывает живейший интерес специалистов IT-индустрии – системных и сетевых администраторов, инженеров, IT-аналитиков, IT-директоров и менеджеров. Можно утверждать, что активные и пло-
2
дотворные дискуссии и обсуждения, обмен опытом и идеями будут проходить не только в конференц-зале, но и в кулуарах. С материалами выступлений можно будет ознакомиться в ближайших номерах журнала и на официальном сайте Семинара: http://SYSM.ru С материалами профсоюза, Уставом, Положениями, протоколами собраний и программой действий можно ознакомиться на официальном сайте профсоюза IT-специалистов: http://ITCU.ru Семинар состоится в субботу, 20 декабря 2003 года в очень уютном и удобном месте – Доме ветеранов кино (ДВК) по адресу: г. Москва, ул. Нежинская, 5. (От м. Киевская на маршрутном такси №7 до остановки «Дом Ветеранов Кино»). Регистрация участников второго Семинара на сайте: http://SYSM.ru Стоимость участия 600 рублей.
календарь событий
ПРОФСОЮЗ IT-СПЕЦИАЛИСТОВ Официальный сайт : http://ITCU.ru Впервые в России появится общественная организация, которая объединит под своим началом всех IT-специалистов, – Межрегиональный Профессиональный союз специалистов в области информационных технологий. Эта идея уже давно обсуждалась в различных интернет-изданиях и на профессиональных конференциях. Теперь она чётко сформировалась и стала реальностью. Странно, но в нашей стране до сих пор не было такого сообщества! Ведь профсоюзы есть у всех – от врачей до журналистов. Профсоюз представляет собой сообщество специалистов, объединённых общими профессиональными интересами и ставит перед собой цель создать организацию, которая будет решать проблемы различного характера, такие как защита прав IT-специалистов, помощь в трудоустройстве, совершенствование профессиональных навыков, повы-
шение и укрепление авторитета профессии IT-специалиста, поддержка высокого уровня образования будущего поколения IT-специалистов, а также будет предоставлять возможность выбирать наиболее выгодную программу пенсионного и медицинского страхования, добиваться различных льгот, в том числе на отдых, мобильную связь и пр. Учредительное собрание Межрегионального Профессионального союза специалистов в области информационных технологий пройдёт 20 декабря 2003 на Семинаре SYSM.02 (http://SYSM.ru). В программе собрания: выборы Правления, обсуждение организационных вопросов, разработка Программы профсоюза на 2004 год. Самое главное – участники Семинара первыми получат возможность стать членами профсоюза.
Резюме Устава Профсоюза Общие положения Ïðîôåññèîíàëüíûé ñîþç ñïåöèàëèñòîâ â îáëàñòè èíôîðìàöèîííûõ òåõíîëîãèé, èìåíóåìûé â äàëüíåéøåì «Ïðîôñîþç», ÿâëÿåòñÿ äîáðîâîëüíûì ñàìîóïðàâëÿåìûì íåêîììåð÷åñêèì ôîðìèðîâàíèåì, îñíîâàííûì íà ÷ëåíñòâå è ñîçäàííûì ïî èíèöèàòèâå ãðàæäàí, ñâÿçàííûõ îáùèìè ïðîèçâîäñòâåííûìè, ïðîôåññèîíàëüíûìè èíòåðåñàìè ïî ðîäó èõ äåÿòåëüíîñòè. Ïðîôñîþç îáúåäèíÿåò ëèö, ðàáîòàþùèõ â îáëàñòè èíôîðìàöèîííûõ òåõíîëîãèé, à òàêæå ó÷àùèõñÿ è ñòóäåíòîâ ó÷åáíûõ çàâåäåíèé, îáó÷àþùèõñÿ ïî ñîîòâåòñòâóþùèì ñïåöèàëüíîñòÿì.
Цели и задачи профсоюза
Çàùèùàòü ïðàâà è èíòåðåñû ÷ëåíîâ ïðîôñîþçà ïî âîïðîñàì èíäèâèäóàëüíûõ òðóäîâûõ è ñâÿçàííûõ ñ òðóäîì îòíîøåíèé. Âûñòóïàòü ñ ïðåäëîæåíèÿìè î ïðèíÿòèè ñîîòâåòñòâóþùèìè îðãàíàìè ãîñóäàðñòâåííîé âëàñòè çàêîíîâ è íîðìàòèâíûõ ïðàâîâûõ àêòîâ, êàñàþùèõñÿ ñîöèàëüíî-òðóäîâîé ñôåðû, à òàêæå èíôîðìàöèîííûõ òåõíîëîãèé. Çàùèùàòü ïðàâà ñâîèõ ÷ëåíîâ ñâîáîäíî ðàñïîðÿæàòüñÿ ñâîèìè ñïîñîáíîñòÿìè ê òðóäó, à òàêæå ïðàâî íà âîçíàãðàæäåíèå çà òðóä áåç êàêîé áû òî íè áûëî äèñêðèìèíàöèè, â òîì ÷èñëå ïî ïîëîâîìó ïðèçíàêó. Ñîãëàñîâûâàòü ñèñòåìû îïëàòû òðóäà, ôîðìû ìàòåðèàëüíîãî ïîîùðåíèÿ, ðàçìåðû òàðèôíûõ ñòàâîê, à òàêæå íîðìû òðóäà ñ ðàáîòîäàòåëÿìè è óïîëíîìî÷åííûìè ãîñóäàðñòâåííûìè îðãàíàìè è çàêðåïëÿòü ñîîòâåòñòâóþùèå ïîëîæåíèÿ â êîëëåêòèâíûõ äîãîâîðàõ è èíûõ äîêóìåíòàõ. Ó÷àñòâîâàòü â ðàññìîòðåíèè îðãàíàìè ãîñóäàðñòâåííîé âëàñòè, îðãàíàìè ìåñòíîãî ñàìîóïðàâëåíèÿ, ðàáîòîäàòåëÿìè, èõ îáúåäèíåíèÿìè ñâîèõ ïðåäëîæåíèé. Ó÷àñòâîâàòü â óðåãóëèðîâàíèè êîëëåêòèâíûõ òðóäîâûõ ñïîðîâ, îðãàíèçîâûâàòü è ïðîâîäèòü â ñîîòâåòñòâèè ñ ôåäåðàëüíûì çàêîíîì çàáàñòîâêè, ìèòèíãè, äåìîíñòðàöèè è äðóãèå êîëëåêòèâíûå äåéñòâèÿ, èñïîëüçóÿ èõ êàê ñðåäñòâî çàùèòû ñîöèàëüíî-òðóäîâûõ ïðàâ è èíòåðåñîâ ðàáîòíèêîâ. Îñóùåñòâëÿòü ïðîôñîþçíûé êîíòðîëü çà ñîáëþäåíèåì ðàáîòîäàòåëÿìè, äîëæíîñòíûìè ëèöàìè çàêîíîäàòåëüñòâà î òðóäå è òðåáîâàòü óñòðàíåíèÿ âûÿâëåííûõ íàðóøåíèé. Îñóùåñòâëÿòü îáó÷åíèå, ïîäãîòîâêó, ïåðåïîäãîòîâêó è ïîâûøåíèå êâàëèôèêàöèè ÷ëåíîâ ïðîôñîþçà. Îñóùåñòâëÿòü þðèäè÷åñêóþ è èíóþ ïîääåðæêó.
Членство в профсоюзе ×ëåíîì ïðîôñîþçà ìîæåò áûòü ëþáîé ãðàæäàíèí ÐÔ, äîñòèãøèé 14ëåòíåãî âîçðàñòà, ïðèçíàþùèé è âûïîëíÿþùèé Óñòàâ ïðîôñîþçà, ðåãóëÿðíî óïëà÷èâàþùèé ÷ëåíñêèå âçíîñû ïðîôñîþçó è ñâÿçàííûé îáùèìè ïðîèçâîäñòâåííûìè è(èëè) ïðîôåññèîíàëüíûìè èíòåðåñàìè ñ èíôîðìàöèîííûìè òåõíîëîãèÿìè, ðàáîòàþùèé â îáëàñòè èíôîðìàöèîííûõ òåõíîëîãèé, ïåíñèîíåð, à òàêæå ó÷àùèéñÿ èëè ñòóäåíò ó÷åáíîãî çàâåäåíèÿ, îáó÷àþùèéñÿ ïî ñîîòâåòñòâóþùåé ñïåöèàëüíîñòè.
№12(13), декабрь 2003
×ëåíû ïðîôñîþçà èìåþò ïðàâî: Ó÷àñòâîâàòü â óïðàâëåíèè ïðîôñîþçîì â ñîîòâåòñòâèè ñ íàñòîÿùèì Óñòàâîì. Èçáèðàòü è áûòü èçáðàííûìè â ðóêîâîäÿùèå è êîíòðîëüíî-ðåâèçèîííûå îðãàíû. Êîíòðîëèðîâàòü äåÿòåëüíîñòü ðóêîâîäÿùèõ îðãàíîâ ïðîôñîþçà. Ó÷àñòâîâàòü â ìåðîïðèÿòèÿõ è ïðîãðàììàõ ïðîôñîþçà. Âíîñèòü íà ðàññìîòðåíèå ðóêîâîäÿùèõ îðãàíîâ ïðåäëîæåíèÿ ïî âîïðîñàì äåÿòåëüíîñòè ïðîôñîþçà. Ïîëó÷àòü íåîáõîäèìóþ èíôîðìàöèþ î äåÿòåëüíîñòè ïðîôñîþçà. Èñïîëüçîâàòü ìàòåðèàëüíî-òåõíè÷åñêóþ áàçó ïðîôñîþçà. Ñîñòîÿòü ÷ëåíîì êàññû âçàèìîïîìîùè (êðåäèòíî-ïîòðåáèòåëüñêîãî ñîþçà). Ïîëó÷àòü áåñïëàòíóþ þðèäè÷åñêóþ ïîìîùü, îêàçûâàåìóþ ïðîôñîþçîì. ×ëåíû ïðîôñîþçà îáÿçàíû: Ñîáëþäàòü íàñòîÿùèé Óñòàâ. Âûïîëíÿòü ðåøåíèÿ ñîáðàíèÿ, Ïðàâëåíèÿ è ïðåäñåäàòåëÿ Ïðàâëåíèÿ. Ïëàòèòü ÷ëåíñêèå âçíîñû. Àêòèâíî ñîäåéñòâîâàòü ðåøåíèþ ñòîÿùèõ ïåðåä ïðîôñîþçîì çàäà÷ ñâîèìè òåõíè÷åñêèìè, èíòåëëåêòóàëüíûìè è äðóãèìè ðåñóðñàìè. Âîçäåðæèâàòüñÿ îò äåéñòâèé, êîòîðûå ìîãóò íàíåñòè óùåðá çàêîííûì èíòåðåñàì ïðîôñîþçà è åãî ÷ëåíîâ.
Структура и управление организацией Ðóêîâîäñòâî ïðîôñîþçîì îñóùåñòâëÿþò: ñîáðàíèå, Ïðàâëåíèå è ïðåäñåäàòåëü Ïðàâëåíèÿ. Ñîáðàíèå ïðîôñîþçà – âûñøèé îðãàí óïðàâëåíèÿ, ïðàâîìî÷íûé ïðèíèìàòü ðåøåíèÿ ïî âñåì âîïðîñàì äåÿòåëüíîñòè ïðîôñîþçà. Ñîáðàíèå ïðîôñîþçà ñîçûâàåòñÿ ïî ìåðå íåîáõîäèìîñòè, íî íå ðåæå îäíîãî ðàçà â 2 ãîäà. Ïðàâëåíèå – îðãàí, ðóêîâîäÿùèé äåÿòåëüíîñòüþ ïðîôñîþçà â ïåðèîä ìåæäó ñîáðàíèÿìè. Ïðàâëåíèå èçáèðàåòñÿ ñîáðàíèåì ïðîôñîþçà èç ÷èñëà ÷ëåíîâ ïðîôñîþçà. Ïðàâëåíèå äåéñòâóåò íà îñíîâàíèè Ïîëîæåíèÿ î Ïðàâëåíèè, ïðèíÿòûì íà Îáùåì ñîáðàíèè ïðîôñîþçà. Çàñåäàíèÿ Ïðàâëåíèÿ ïðîâîäÿòñÿ ïî ìåðå íåîáõîäèìîñòè, íî íå ðåæå îäíîãî ðàçà â êâàðòàë. Ïðåäñåäàòåëü Ïðàâëåíèÿ èçáèðàåòñÿ Ïðàâëåíèåì èç ÷èñëà ÷ëåíîâ Ïðàâëåíèÿ. Ïðåäñåäàòåëü Ïðàâëåíèÿ ïîäîò÷åòåí ñîáðàíèþ è Ïðàâëåíèþ, îðãàíèçóåò âûïîëíåíèå ðåøåíèé ñîáðàíèÿ è Ïðàâëåíèÿ. Ïåðâè÷íàÿ ïðîôñîþçíàÿ îðãàíèçàöèÿ – îñíîâà ñòðóêòóðû Ïðîôñîþçà – äîáðîâîëüíîå îáúåäèíåíèå íå ìåíåå 3-õ ÷ëåíîâ ïðîôñîþçà, äåéñòâóþùåå íà îñíîâàíèè Ïîëîæåíèÿ, ïðèíÿòîãî èì â ñîîòâåòñòâèè ñ íàñòîÿùèì Óñòàâîì, èëè íà îñíîâàíèè îáùåãî Ïîëîæåíèÿ î ïåðâè÷íîé îðãàíèçàöèè ïðîôñîþçà, óòâåðæäåííîãî Ïðàâëåíèåì ïðîôñîþçà. Âûñøèì îðãàíîì ïåðâè÷íîé ïðîôñîþçíîé îðãàíèçàöèè ÿâëÿåòñÿ ñîáðàíèå åå ÷ëåíîâ. Ðàáîòíèêè îäíîãî ïðåäïðèÿòèÿ, ó÷ðåæäåíèÿ, îðãàíèçàöèè, ó÷àùèåñÿ è ïðåïîäàâàòåëè ó÷åáíûõ çàâåäåíèé îáúåäèíÿþòñÿ, êàê ïðàâèëî, â îäíó ïåðâè÷íóþ ïðîôñîþçíóþ îðãàíèçàöèþ.
3
программирование
ПРАКТИЧЕСКИЕ СОВЕТЫ ПО ВОССТАНОВЛЕНИЮ СИСТЕМЫ В БОЕВЫХ УСЛОВИЯХ 1. Во время исполнения ошибки имеют наивысший приоритет. Прервать исполнение ошибки может только другая, более активная ошибка. 2. Запросы операционной системы к ошибкам ошибками могут игнорироваться. 3. Запросы ошибок к операционной системе игнорироваться не могут. 4. При работе с файлами ошибки могут пользоваться файловой системой базовой ОС и ее ошибками. 5. На ЭВМ с параллельной архитектурой может выполняться несколько ошибок одновременно. В. Тихонов «Теория ошибок»
Практически всем администраторам приходилось сталкиваться с теми или иными сбоями ОС и ее окружения, но далеко не все могли быстро найти источник их возникновения (особенно если сбой происходит не регулярно и на чужой машине). Тем не менее существует несколько вполне универсальных стратегий поиска дефективных компонентов, разработанных и апробированных еще со времен ЕС и мейнфреймов. Вот о них-то и рассказывает настоящая статья.
КРИС КАСПЕРСКИ 6
программирование Типичная реакция домашнего пользователя на нестабильность работы своей машины – полная переустановка операционной системы. Иногда это помогает, иногда – нет, но, как бы там ни было, переустановка операционной системы на сервере – достаточно грандиозное событие, самое малое на целый день выводящее локальную сеть фирмы из игры. Квалифицированный администратор отличается от неквалифицированного в первую очередь тем, что со всеми проблемами справляется на лету, до минимума сводя время простоя сети. Вообще-то хорошо отлаженная система, базирующаяся на ОС типа FreeBSD (или подобной ей), способна без сбоев работать годами, не требуя к себе совершенно никакого внимания. Системы, построенные на базе Windows NT, этим, увы, похвастаться не могут, и для достижения сколь-нибудь стабильной работы за ними приходится постоянно ухаживать. Аппаратное обеспечение, собираемое на коленках в ближайшем подвале, также не отличается высокой надежностью, а отличить качественную подделку от оригинала по внешним признакам достаточно трудно. На просторах России свободно продаются отбракованные чипы, левым путем добытые у производителей и выдаваемые за настоящие. Кстати, многие из именитых производителей грешат передачей своих торговых марок третьим фирмам, выпускающим довольно посредственное оборудование, но продающих его по «брэндовским» ценам. Яркий тому пример – пишущий привод TEAC 552E, к которому фирма TEAC вообще не имеет никакого отношения. Про материнские платы и модули памяти вообще говорить не стоит. Их клепают все кому не лень, и многие модели вообще не работают, кое-как запускаясь на пониженных таймингах и частотах. Словом, если сбой старушки БЭСМ-6 был настоящим ЧП, то зависание современного сервера – вполне обычное дело, воспринимаемое администраторами как неизбежное зло. Эта статья не убережет вас ни от критических ошибок приложений, ни от отказа оборудования, но, по крайней мере, научит быстро и безошибочно находить их источник. Речь пойдет преимущественно о Windows NT и производных от нее системах (Windows 2000, Windows XP), хотя поклонники UNIX также найдут здесь немало интересного.
Аппаратная часть Вот два основных аппаратных виновника нестабильной работы системы – оперативная память и блок питания. Рассмотрим их поподробнее, отмечая особенности взаимодействия с памятью в современных чипсетах, таких как Intel 875P и подобных ему. Тесная связь между программным и аппаратным обеспечением затрудняет деление статьи на две равные части, поскольку ряд сбоев системы (и пресловутых голубых экранов смерти – в том числе) вызван отнюдь не алгоритмическими ошибками, а неисправностью железа. Но на начальном этапе анализа «голубого экрана смерти» (далее по тексту просто голубого экрана) мы не можем надежно установить его источник и, чтобы не описывать одни и те же методики дважды, условимся относить все критические ошибки системы к программной среде. В действительности же это не вызывает никакого противоре-
№12(13), декабрь 2003
чия, поскольку с аппаратными ошибками приходится бороться и программными средствами (помните известное: «как нематериальная душа возвращается в тело в результате материальных действий врача?»).
Оперативная память Оперативная память относится к одному из наименее надежных компонентов вычислительной системы, и потому львиная доля всех сбоев приходится именно на нее. Проявления их могут быть самыми разнообразными: от критических ошибок приложений до периодических или непериодических ошибок чтения (записи) на жесткий диск или даже каскадных ошибок приема/передачи TCP/IP-пакетов (что не покажется удивительным, если вспомнить о кэширующем приводе всех драйверов, обслуживающих устройства ввода/вывода). Любой аппаратный ресурс, требующий для своей работы некоторого количества оперативной памяти, так или иначе зависим от работоспособности последней. Существует мнение, что память «с четностью» полностью решает проблему своей надежности и сводит риск разрушения данных к разумному минимуму. На самом деле это не так. Память с четностью распознает лишь одиночные ошибки и не гарантирует обнаружение групповых. Память типа ECC (Error Check & Correction/Error Correction Code – Контроль и Исправление Ошибок), способна автоматически исправлять любые одиночные ошибки и обнаруживать любые двойные. До тех пор, пока оперативная память функционирует более или менее нормально, противостояние энтропии и помехозащитных кодов решается в пользу последних. Однако при полном или частичном выходе одного или нескольких модулей памяти из строя корректирующих способностей контролирующих кодов перестает хватать, и система начинает работать крайне нестабильно. Концепция виртуальной памяти, реализованная в операционных системах семейства Windows и UNIX, рассматривает основную оперативную память как своеобразный кэш. А это значит, что одни и те же логические страницы адресного пространства в разное время могут отображаться на различные физические адреса. Разрушение однойединственной физической ячейки памяти затрагивает множество виртуальных ячеек, и потому сбои памяти практически всегда проявляются «коллективными» критическими ошибками приложений, рассредоточенными в широком диапазоне адресов. Если же критические ошибки возникают лишь в некоторых процессах и располагаются по более или менее постоянным адресам – с высокой степенью вероятности можно предположить, что это программная, а не аппаратная ошибка. Исключение составляет неоткачиваемая область памяти (non-paged pool), занятая ядром системы и всегда размещающаяся по одним и тем же физическим адресам. Наличие дефективных ячеек в данной области обычно приводит к синему экрану смерти и/или полному зависанию системы, хотя в некоторых случаях ошибки драйверов передаются на прикладной уровень и роняют один или несколько процессов. Самое интересное, что при прогоне нестабильно работающих драйверов/процессом под отладчиком ошибка волшебным образом может исчезать. В действительности ничего загадочного тут нет. За счет многократного снижения
7
программирование интенсивности доступа к памяти отладчик позволяет «вытянуть» даже дефективные ячейки, затрудняя их локализацию. Некоторые руководства рекомендуют исследовать дамп, сброшенный системой при возникновении критической ошибки в ядре системы, наивно надеясь на то, что искаженные ячейки будут выглядеть как бессмысленный мусор, сразу бросающийся в глаза даже при минимальных навыках дизассемблирования. При разрушении большого количества ячеек памяти, затрагивающих исполняемый код, это действительно так. Однако искажение областей данных предложенный алгоритм выявить не в состоянии. Только чрезвычайно опытный разработчик драйверов заподозрит, что здесь что-то не так. А ведь в некоторых случаях неисправный модуль содержит всего лишь один-единственный дефективный бит информации, который при визуальном осмотре дампа вообще нереально обнаружить. К тому же не стоит забывать, что «замусоривание» памяти может быть вызвано не только аппаратными, но и программными ошибками (например, программист забыл проинициализировать буфера или направил указатели в «космос», передав управление по произвольному адресу памяти). Худший случай – это разрушение буферов ввода/вывода, зачастую приводящее к полному краху файловой системы без какой-либо надежды на ее восстановление. По непонятной причине разработчики дисковых драйверов отказались от подсчета контрольной суммы пересылаемых через них блоков данных, что сделало файловую систему чрезвычайно уязвимой. Причем NTFS оказывается даже в худшей ситуации, чем FAT32, поскольку требует значительно меньшего объема буферной памяти для своей поддержки и к тому же значительно легче поддается «ручному» восстановлению. Автор настоящей статьи использует отказоустойчивые буфера, построенные на основе демонстрационных драйверов, входящих в состав DDK, и дополненные специальными средствами контроля. Главное ноухау данной технологии состоит в том, что обмен с диском ведется на «сыром» (RAW MODE) уровне, т.е. помимо области пользовательских данных в сектор входит контрольная сумма, по которой драйвер с одной и привод с другой стороны контролируют целостность данных. В жизни автора эта технология срабатывала дважды (т.е. выявляла дефективный модуль памяти, пытавшийся разрушить жесткий диск), так что усилия, затраченные на разработку драйверов, многократно окупили себя сполна! Кстати, тестирование оперативной памяти путем прогона специальных программ (Check It, PC Diagnostic и им подобных) – не самый лучший путь для выявления ее работоспособности. В силу физической неоднородности подсистемы памяти дефективность бракованных модулей зачастую проявляется не на любой, а на строго определенной последовательности запросов и при определенном сочетании содержимого разрушенной и окрестных ячеек. Тестирующие программы перебирают ограниченное количество наиболее типичных шаблонов и потому обнаруживают лишь некоторые, наиболее дефективные дефекты. Ряд серверных чипсетов содержит в себе более или менее продвинутые средства тестирования памяти, работающие в фоновом режиме и работающие достаточно эффективно.
8
Ряд тестовых пакетов, таких, например, как TestMem от SERJ_M, перебирают большое количество разнотипных шаблонов и довольно лихо выявляют скрытые дефекты модулей памяти, в обычной жизни проявляющиеся лишь при стечении множества маловероятных обстоятельств. К сожалению, эволюция чипсетов в конце концов привела к тому, что и эти шаблоны перестали работать. При слишком интенсивном обмене с памятью чипсет Intel 875P и другие подобные ему чипсеты начинают вставлять холостые циклы, давая памяти время «остыть», предотвращая тем самым ее перегрев. С одной стороны, такое конструкторское решение можно только приветствовать, поскольку оно значительно повышает надежность системы, но с другой – чрезвычайно затрудняет ее тестирования. Для получения сколь-нибудь достоверных результатов тестирующая программа должна подобрать такую интенсивность прогона памяти, при которой холостые циклы еще не вставляются, но система работает уже на пределе. Насколько известно автору, подобных программ еще нет и когда они появятся на рынке – неизвестно. Так что спасение утопающих – забота самих утопающих. Сама по себе память, может быть, и не виновата. Источником ошибок вполне может быть и северный мост чипсета, содержащий контроллер памяти. Исследуя чипсет VIA KT133, автор обнаружил несколько критических ошибок планировщика очередей, приводящих к искажению передаваемых данных и визуально проявляющихся как типичные дефекты памяти.
Блок питания Второй по распространенности источник нестабильной работы компьютера – это блок питания. Современные компьютеры предъявляют к качеству питающего напряжения достаточно жесткие требования, при нарушении которых работа компьютера становится совершенно непредсказуемой, проявляясь зависаниями, критическими ошибками и голубыми экранами смерти, выскакивающими в самых неожиданных местах. В ряде случаев отмечается замедление быстродействия приводов, обычно носящее характер внезапных провалов производительности (копирование файлов движется как бы рывками). Практически все уважающие себя производители материнских плат оснащают свои детища развитой электронной системой контроля основных (опорных) напряжений, показания которых отображаются специальными утилитами. Убедитесь, что питающий потенциал соответствует норме, отклонясь от нее не более чем на 5-10%, и остается более или менее постоянным в процессе работы компьютера. Причем «недобор» напряжения намного более опасен, чем «перебор». Увеличение потенциала на 15-20% практически никогда не приводит к моментальному выходу электроники из строя, правда, вызывает ее перегрев, но при наличии качественной системы охлаждения с этим можно и смириться. Но даже незначительное уменьшение потенциала заметно снижает реакционность переходных процессов полупроводниковых элементов, и система не успевает поспевать за тактовой частотой, что приводит к зависаниям, критическим ошибкам, перезагрузкам и т. д.
программирование На рисунке 1 приведен плохой блок питания, обнаруживающий значительную просадку на линии 12 вольт и чудовищные пульсации напряжения. Линия 3.3 вольт, обслуживающая святую святых – оперативную память, также слегка пульсирует, хотя стабилизируется отнюдь не блоком питания, но самой материнской платой, предел стабилизации которой, впрочем, тоже небезграничен, и даже качественная материнская плата бессильна выправить кривой от рождения блок питания.
Ðèñóíîê 1. Ïðèìåð ïëîõîãî áëîêà ïèòàíèÿ
К сожалению, точность интегрированных вольтметров достаточно невелика, и многие из них явно нуждаются в хорошей калибровке. Поэтому доверять таким показаниям следует с осторожностью и большой долей скептицизма, при необходимости уточняя их нормальным цифровым мультиметром.
…и все-все-все Остальные компоненты компьютера практически никогда не вызывают серьезных проблем. Процессоры (при надлежащей системе охлаждения и не слишком большой тактовой частоте, конечно) лишь в исключительных случаях позволяют себе подвесить систему (да и то основная доля вины ложится не на сам процессор, а на интегрированный кэш). Кстати, характерная болезнь «разогнанных процессоров» – голубой экран с надписью «UNEXPECTED_KERNEL_MODE_TRAP» (подробнее об этом рассказывается во второй части статьи). Жесткие диски, становясь все более и более интеллектуальными устройствами, достаточно неприхотливы, правда, при неправильной установке терминаторов на SCSI-устройствах Windows NT может выбрасывать голубой экран смерти, но хорошие диски термируют себя самостоятельно. Карты расширения от сторонних производителей, будучи расположенными на разделяемой PCI-шине, способны вызывать любые мыслимые и немыслимые конфликты, поэтому не пользуйтесь продукцией тех поставщиков, которым вы не доверяете.
Если ошибка будет повторяться, обратитесь к разработчику». К несчастью, критические ошибки приложения (в терминологии Windows 2000 просто «ошибки приложения») имеют устойчивую тенденцию появляться в самые ответственные моменты времени, например, накануне сдачи финансового отчета. А разработчики… они в большинстве своем такие сообщения просто игнорируют. Иногда потому, что просто не знают, как эту информацию интерпретировать, иногда потому, что вообще не заботятся о проблемах своих пользователей. Многие сетуют на тупость Windows и ее неспособность противостоять критическим ошибкам. Но эти обвинения совершенно безосновательны. Возникновение критической ошибки свидетельствует о том, что программа поехала крышей и пошла вразнос. Все, что только операционная система может сделать, – это пристрелить ее, в противном случае программа возвратит заведомо неверные данные, чего допускать ни в коем случае нельзя. Так что операционную систему не ругать следует, а благодарить! Иногда сообщения о критических ошибках удается предотвратить установкой нового сервис-пака, а иногда, наоборот, – путем удаления нового. Еще можно попробовать переустановить операционную систему или только само нестабильно работающее приложение. Однако никаких гарантий, что после всех этих манипуляций сбой действительно у вас исчезнет, нет. Достаточно вспомнить нашумевшую историю с червем MSBLASTER, вызывающим критическую ошибку в системном сервисе svchost. Но сколько бы вы ни переустанавливали свою Windows 2000, сколько бы ни меняли железо, ситуация не улучшалась. Антивирусы, правда, сообщали о наличии вируса на компьютере (да и то не всегда), однако не объясняли, какие меры безопасности следует принять. К тому же обрушение сервиса svchost происходило отнюдь не вследствие инфицирования компьютера вирусом, а лишь при неудачной попытке оного. Именно неумение хакеров сорвать стек, не уронив при этом всю систему, и демаскировало вирус, попутно организовав разрушительную DoS-атаку, до сих пор приносящую весьма ощутимые убытки. Всякий администратор, считающий себя профессионалом, не может позволить себе роскошь действовать вслепую. Знание ассемблера и умение быстро и грамотно интерпретировать сообщения о критических ошибках, если еще не решит проблему, то, по крайней мере, придаст вам чувство уверенности и поможет локализовать истинного виновника нестабильности системы. Во всяком случае будет куда ткнуть носом зарвавшегося разработчика. Согласитесь, одно дело догадываться об ошибке и совсем другое – показывать на нее пальцем.
Программная часть
Приложения, недопустимые операции и все-все-все
Катастрофическая небрежность тестирования фирменного и кустарного ПО приводит к появлению многочисленных критических ошибок при его исполнении: «Программа выполнила недопустимую операцию и будет закрыта.
Различные операционные системы по-разному реагируют на критические ошибки. Так, например, Windows NT резервирует два региона своего адресного пространства для выявления некорректных указателей. Один находит-
№12(13), декабрь 2003
9
программирование ся на самом «дне» карты памяти и предназначен для отлавливания нулевых указателей. Другой расположен между «кучей» и областью памяти, закрепленной за операционной системой. Он контролирует выход за пределы пользовательской области памяти и, вопреки расхожему мнению, никак не связан в функцией WriteProcessMemory (см. техническую заметку ID: Q92764 в MSDN). Оба региона занимают по 64 Кб, и всякая попытка доступа к ним расценивается системой как критическая ошибка. В Windows 9x имеется всего лишь один 4 Кб регион, следящий за нулевыми указателями, поэтому по своим контролирующим способностям она значительно уступает NT. В Windows NT экран критической ошибки (см. рис. 2) содержит следующую информацию: адрес машинной инструкции, возбудившей исключение; словесное описание категории исключения (или его код, если категория исключения неизвестна); параметры исключения (адрес недействительной ячейки памяти, род операции и т. д.).
Ðèñóíîê 2. Ñîîáùåíèå î êðèòè÷åñêîé îøèáêå, âûäàâàåìîå îïåðàöèîííîé ñèñòåìîé Windows 2000
Операционные системы семейства Windows 9x в этом отношении намного более информативны (см. рис. 3) и помимо категории исключения выводят содержимое регистров ЦП на момент сбоя, состояние стека и байты памяти по адресу CS:EIP (т.е. текущему адресу исполнения). Впрочем, наличие «Доктора Ватсона» (о нем – далее) стирает различие между двумя системами, и потому можно говорить лишь об удобстве и эргономике 9x, сразу предоставляющей весь минимум необходимых сведений, в то время как в NT отчет об ошибке создается отдельной утилитой.
Если никакой из отладчиков в системе не установлен, то окно о критической ошибке имеет всего лишь одну кнопку – кнопку «ОК», нажатие которой приводит к аварийному закрытию политнекорректного приложения. При желании окно критической ошибки можно оснастить кнопкой «Отмена» («Cancel»), запускающей отладчик или иную утилиту анализа ситуации. Важно понять, что «Отмена» отнюдь не отменяет автоматическое закрытие приложения, но при некоторой сноровке вы можете устранить «пробоину» вручную, продолжив нормальную работу1.
Доктор Ватсон «Доктор Ватсон» является штатным обработчиком критических ошибок, входящим в базовый пакет поставки всех операционных систем семейства Windows. По своей природе он представляет статическое средство сбора релевантной информации. Предоставляя исчерпывающий отчет о причинах сбоя, «Доктор Ватсон» в то же самое время лишен активных средств воздействия на некорректно работающие программы. Утихомирить разбушевавшееся приложение, заставив его продолжить свою работу с помощью одного «Доктора Ватсона», вы не сможете, и для этого вам придется прибегать к интерактивным отладчикам, одним из которых является Microsoft Visual Studio Debugger, входящий в состав одноименной среды разработки и рассматриваемый в статье далее. Считается, что «Доктор Ватсон» предпочтительнее использовать на рабочих станциях (точнее, на автоматизированных рабочих местах), а интерактивные средства отладки – на серверах. Дескать, во всех премудростях ассемблера пользователи все равно не разбираются, а вот на сервере продвинутый отладчик будет как нельзя кстати. Отчасти это действительно так, но не стоит игнорировать то обстоятельство, что далеко не все источники ошибок обнаруживаются статическими средствами анализа, к тому же интерактивные инструменты значительно упрощают процедуру анализа. С другой стороны, «Доктор Ватсон» достается нам даром, а все остальные программные пакеты приходится приобретать за дополнительную плату. Так что предпочтительный обработчик критических ошибок вы должны выбирать сами. Для установки «Доктора Ватсона» отладчиком по умолчанию добавьте в реестр следующую запись или запустите файл Drwtsn32.exe c ключом «–i» (для выполнения обоих действий вы должны иметь права администратора): Ëèñòèíã 1. Óñòàíîâêà «Äîêòîðà Âàòñîíà» îòëàä÷èêîì ïî óìîë÷àíèþ
Ðèñóíîê 3. Ñîîáùåíèå î êðèòè÷åñêîé îøèáêå, âûäàâàåìîå îïåðàöèîííîé ñèñòåìîé Windows 98 1
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\ ↵ CurrentVersion\AeDebug] "Auto"="1" "Debugger"="drwtsn32 -p %ld -e %ld -g" "UserDebuggerHotKey"=dword:00000000
Запустите «Редактор Реестра» и перейдите в раздел «HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug». Если такого раздела нет – создайте его самостоятельно. Строковой параметр «Debugger» задает путь к файлу отладчика со всеми необходимыми ключами; строковой параметр «Auto» указывает, должен ли отладчик запускаться автоматически (значение «1») или предлагать пользователю свободу выбора («0»). Наконец двойное слово параметра «UserDebuggerHotKey» специфицирует скэн-код горячей клавиши для принудительного вызова отладчика.
10
программирование Теперь возникновение критических ошибок программы станет сопровождаться генерацией отчета, составляемого «Доктором Ватсоном» и содержащим более или менее подробные сведения о характере ее происхождения.
eax=00000064 ebx=7ffdf000 ecx=00000000 edx=00000064 ↵ esi=00000000 edi=00000000 eip=00401014 esp=0012ff70 ebp=0012ffc0 iopl=0 ↵ nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000202 ; Ñîäåðæèìîå ðåãèñòðîâ è ôëàãîâ.
↵
ôóíêöèÿ: <nosymbols> ; Ðàñïå÷àòêà îêðåñòíîé òî÷êè cáîÿ.
Ðèñóíîê 4. Ðåàêöèÿ «Äîêòîðà Âàòñîíà» íà êðèòè÷åñêóþ îøèáêó
Образец дампа, созданный «Доктором Ватсоном», приведен ниже. Комментарии, добавленные автором, выделены красным цветом: Ëèñòèíã 2. Îáðàçåö îò÷åòà «Äîêòîðà Âàòñîíà» Èñêëþ÷åíèå â ïðèëîæåíèè: Ïðèë.: (pid=612) ; pid ïðîöåññà, â êîòîðîì ïðîèçîøëî èñêëþ÷åíèå. Âðåìÿ: 14.11.2003 @ 22:51:40.674 ; Âðåìÿ, êîãäà ïðîèçîøëî èñêëþ÷åíèå. Íîìåð: c0000005 (íàðóøåíèå ïðàâ äîñòóïà) ; Êîä êàòåãîðèè èñêëþ÷åíèÿ. ; Ðàñøèôðîâêó êîäîâ èñêëþ÷åíèé ìîæíî íàéòè â WINNT.H ; âõîäÿùèì â ñîñòàâ SDK, ïðèëàãàåìîì ê ëþáîìó ; Windows-êîìïèëÿòîðó. Ïîäðîáíîå îïèñàíèå âñåõ èñêëþ÷åíèé ; ñîäåðæèòñÿ â äîêóìåíòàöèè ïî ïðîöåññîðàì Intel è AMD, ; áåñïëàòíî ðàñïðîñòðàíÿåìîé èõ ïðîèçâîäèòåëÿìè (âíèìàíèå: ; äëÿ ïåðåâîäà êîäà èñêëþ÷åíèÿ îïåðàöèîííîé ñèñòåìû â ; âåêòîð ïðåðûâàíèÿ ÖÏ, âû äîëæíû îáíóëèòü ñòàðøåå ñëîâî), ; â äàííîì ñëó÷àå ýòî 0x5 – ïîïûòêà äîñòóïà ê ïàìÿòè ; ïî çàïðåùåííîìó àäðåñó. *----> Ñâåäåíèÿ î ñèñòåìå <----* Èìÿ êîìïüþòåðà: KPNC Èìÿ ïîëüçîâàòåëÿ: Kris Kaspersky ×èñëî ïðîöåññîðîâ: 1 Òèï ïðîöåññîðà: x86 Family 6 Model 8 Stepping 6 Âåðñèÿ Windows 2000: 5.0 Òåêóùàÿ ñáîðêà: 2195 Ïàêåò îáíîâëåíèÿ: None Òåêóùèé òèï: Uniprocessor Free Çàðåãèñòðèðîâàííàÿ îðãàíèçàöèÿ: Çàðåãèñòðèðîâàííûé ïîëüçîâàòåëü: Kris Kaspersky ; Êðàòêèå ñâåäåíèÿ î ñèñòåìå. *----> Ñïèñîê çàäà÷ <----* 0 Idle.exe 8 System.exe 232 smss.exe … 1244 os2srv.exe 1164 os2ss.exe 1284 windbg.exe 1180 MSDEV.exe 1312 cmd.exe 612 test.exe 1404 drwtsn32.exe 0 _Total.exe (00400000 - 00406000) (77F80000 - 77FFA000) (77E80000 - 77F37000) ; Ïåðå÷åíü çàãðóæåííûõ DLL. ; Ñîãëàñíî äîêóìåíòàöèè, ñïðàâà îò àäðåñîâ äîëæíû áûòü ; ïåðå÷èñëåíû èìåíà ñîîòâåòñòâóþùèõ ìîäóëåé, îäíàêî ; ïðàêòè÷åñêè âñå îíè òàê õîðîøî «çàìàñêèðîâàëèñü», ÷òî ñòàëè ; ñîâåðøåííî íå âèäíû. Âûòàùèòü èõ èìåíà èç ôàéëà ïðîòîêîëà ; âñå-òàêè ìîæíî, íî ïðèäåòñÿ íåìíîãî «ïîøàìàíèòü» (ñì. íèæå ; «òàáëèöó ñèìâîëîâ»). Êîïèÿ ïàìÿòè äëÿ ïîòîêà 0x188 ; Íèæå èäåò êîïèÿ ïàìÿòè ïîòîêà, âûçûâàâøåãî èñêëþ÷åíèå.
№12(13), декабрь 2003
00400ffc 0000 add [eax],al ds:00000064=?? ; Çàïèñûâàåì â ÿ÷åéêó, íà êîòîðóþ ññûëàåò EAX, çíà÷åíèå AL. ; Çíà÷åíèå àäðåñà ÿ÷åéêè, âû÷èñëåííîé Äîêòîðîì Âàòñîíîì, ; ðàâíî 64h, ÷òî, î÷åâèäíî, íå ñîîòâåòñòâóåò ; äåéñòâèòåëüíîñòè. «Äîêòîð Âàòñîí» ïîäñòàâëÿåò â âûðàæåíèå ; çíà÷åíèå ðåãèñòðà EAX íà ìîìåíò âîçíèêíîâåíèÿ ñáîÿ, ; è ýòî ñîâñåì íå òî çíà÷åíèå, êîòîðîå áûëî â ìîìåíò ; èñïîëíåíèÿ! Ê ñîæàëåíèþ, ÷åìó áûë ðàâåí EAX â ìîìåíò ; èñïîëíåíèÿ íè íàì, íè «Äîêòîðó Âàòñîíó» íå èçâåñòåí. 00400ffe 0000 add [eax],al ds:00000064=?? ; Çàïèñûâàåì â ÿ÷åéêó, íà êîòîðóþ ññûëàåò EAX, çíà÷åíèå AL. ; Êàê? Îïÿòü? Âîîáùå-òî òàê êîäèðóåòñÿ ïîñëåäîâàòåëüíîñòü ; 00 00 00 00, ïî âñåé âèäèìîñòè ÿâëÿþùàÿñÿ îñêîëêîì ; íåêîòîðîé ìàøèííîé êîìàíäû, íåïðàâèëüíî ; èíòåðïðåòèðîâàííîé äèçàññåìáëåðíûì äâèæêîì ; «Äîêòîðà Âàòñîíà». 00401000 8b542408 mov edx,[esp+0x8] ss:00f8d547=???????? ; Çàãðóæàåì â EDX àðãóìåíò ôóíêöèè. ; Êàêîé èìåííî àðãóìåíò – ñêàçàòü íåâîçìîæíî, ò.ê. ìû íå ; çíàåì àäðåñ ñòåêîâîãî ôðåéìà. 00401004 33c9 ; Îáíóëÿåì ECX
xor
ecx,ecx
00401006 85d2 test edx,edx 00401008 7e18 jle 00409b22 ; Åñëè EDX == 0, ïðûãàåì íà àäðåñ 409B22h. 0040100a 8b442408 mov eax,[esp+0x8] ss:00f8d547=???????? ; Çàãðóæàåì óæå óïîìÿíóòûé àðãóìåíò â ðåãèñòð EAX. 0040100e 56 push esi ; Ñîõðàíÿåì ESI â ñòåêå, ïåðåìåùàÿ òåì ñàìûì óêàçàòåëü ; âåðøèíû ñòåêà íà 4 áàéòà ââåðõ (â îáëàñòü ìëàäøèõ ; àäðåñîâ). 0040100f 8b742408 mov esi, [esp+0x8] ss:00f8d547=???????? ; Çàãðóæàåì â ESI î÷åðåäíîé àðãóìåíò. ; Ïîñêîëüêó ESP áûë òîëüêî ÷òî èçìåíåí, ýòî ñîâñåì íå òîò ; àðãóìåíò, ñ êîòîðûì ìû èìåëè äåëî ðàíåå. 00401013 57 push edi ; Ñîõðàíÿåì ðåãèñòð EDI â ñòåêå. ÑÁÎÉ -> 00401014 0fbe3c31 movsx edi,byte ptr [ecx+esi] ↵ ds:00000000=?? ; Âîò ìû è äîáðàëèñü äî èíñòðóêöèè, âîçáóäèâøåé èñêëþ÷åíèå ; äîñòóïà. Îíà îáðàùàåòñÿ ê ÿ÷åéêå ïàìÿòè, íà êîòîðóþ ; óêàçûâàåò ñóììà ðåãèñòðîâ ECX è ESI, à ÷åìó ðàâíî èõ ; çíà÷åíèå? Ïðîêðó÷èâàåì ýêðàí íåìíîãî ââåðõ è íàõîäèì, ÷òî ; ECX è ESI ðàâíû 0, î ÷åì «Äîêòîð Âàòñîí» íàì è ñîîáùàåò: ; «ds:000000» îòìåòèì, ÷òî ýòîé èíôîðìàöèè ìîæíî âåðèòü, ; ïîñêîëüêó ïîäñòàíîâêà ýôôåêòèâíîãî àäðåñà îñóùåñòâëÿëàñü ; íåïîñðåäñòâåííî â ìîìåíò èñïîëíåíèÿ, òåïåðü âñïîìíèì, ; ÷òî ESI ñîäåðæèò êîïèþ ïåðåäàííîãî ôóíêöèè àðãóìåíòà ; è ÷òî ECX áûë îáíóëåí ÿâíî, ñëåäîâàòåëüíî, â âûðàæåíèè ; [ECX+ESI] ðåãèñòð ESI – óêàçàòåëü, à ECX – èíäåêñ. Ðàç ESI ; ðàâåí íóëþ, òî íàøåé ôóíêöèè ïåðåäàëè óêàçàòåëü ; íà íåâûäåëåííóþ îáëàñòü ïàìÿòè. Îáû÷íî ýòî ïðîèñõîäèò ; ëèáî âñëåäñòâèå àëãîðèòìè÷åñêîé îøèáêè â ïðîãðàììå, ; ëèáî âñëåäñòâèå èñ÷åðïàíèÿ âèðòóàëüíîé ïàìÿòè, ; ê ñîæàëåíèþ, «Äîêòîð Âàòñîí» íå îñóùåñòâëÿåò ; äèçàññåìáëèðîâàíèå ìàòåðèíñêîé ôóíêöèè, è êàêîé èç äâóõ ; ïðåäïîëàãàåìûõ âàðèàíòîâ ïðàâèëüíûé – íàì îñòàåòñÿ ëèøü ; ãàäàòü… Ïðàâäà, ìîæíî äèçàññåìáëèðîâàòü äàìï ïàìÿòè ; ïðîöåññà (åñëè, êîíå÷íî, îí áûë ñîõðàíåí), íî ýòî óæå ; íå òî… 00401018 03c7 add eax, edi ; Ñëîæèòü ñîäåðæèìîå ðåãèñòðà EAX ñ ðåãèñòðîì EDI ; è çàïèñàòü ðåçóëüòàò â EAX. 0040101a 41 inc ecx ; Óâåëè÷èòü ECX íà åäèíèöó.
11
программирование 0040101b 3bca cmp ecx,edx 0040101d 7cf5 jl 00407014 ; Äî òåõ ïîð ïîêà ECX < EDX, ïåðåõîäèòü íà àäðåñ 407014 ; (î÷åâèäíî, ìû èìååì äåëî ñ öèêëîì, óïðàâëÿåìûì ñ÷åò÷èêîì ; ECX). Ïðè èíòåðàêòèâíîé îòëàäêå ìû ìîãëè áû ïðèíóäèòåëüíî ; âûéòè èç ôóíêöèè, âîçâðàòèâ ôëàã îøèáêè, ÷òîáû ìàòåðèíñêàÿ ; ôóíêöèÿ (à ñ íåé è âñÿ ïðîãðàììà öåëèêîì) ìîãëà ïðîäîëæèòü ; ñâîå âûïîëíåíèå, è â ýòîì ñëó÷àå ïîòåðÿííîé îêàæåòñÿ ëèøü ; ïîñëåäíÿÿ îïåðàöèÿ, íî âñå îñòàëüíûå äàííûå îêàæóòñÿ ; íåèñêàæåííûìè. 0040101f 5f pop edi 00401020 5e pop esi 00401021 c3 ret ; Âûõîäèì èç ôóíêöèè. *----> Îáðàòíàÿ òðàññèðîâêà ñòåêà <----* ; Ñîäåðæèìîå ñòåêà íà ìîìåíò âîçíèêíîâåíèÿ ñáîÿ. ; Ðàñïå÷àòûâàåò àäðåñà è ïàðàìåòðû ïðåäûäóùèõ âûïîëíÿåìûõ ôóíêöèé, ; ïðè èíòåðàêòèâíîé îòëàäêå ìû ìîãëè áû ïðîñòî ïåðåäàòü óïðàâëåíèå ; íà îäíó èç âûøåëåæàùèõ ôóíêöèé, ÷òî ýêâèâàëåíòíî âîçâðàùåíèþ ; â ïðîøëîå, ýòî òîëüêî â ðåàëüíîé æèçíè ðàçáèòóþ ÷àøêó ; âîññòàíîâèòü íåëüçÿ, â êîìïüþòåðíîé âñåëåííîé âîçìîæíî âñå! FramePtr ReturnAd Param#1 Param#2 Param#3 Param#4 ↵ Function Name ; FramePtr: Óêàçûâàåò íà çíà÷åíèå ôðåéìà ñòåêà, ; âûøå (ò.å. â áîëåå ìëàäøèõ àäðåñàõ) ; ñîäåðæàòñÿ àðãóìåíòû ôóíêöèè, íèæå – åå ; ëîêàëüíûå ïåðåìåííûå. ; ; ReturnAd: Áåðåæíî õðàíèò àäðåñ âîçâðàòà â ìàòåðèíñêóþ ; ôóíêöèþ. Åñëè çäåñü ñîäåðæèòñÿ ìóñîð è ; îáðàòíàÿ òðàññèðîâêà ñòåêà íà÷èíàåò ; õàðàêòåðíî øóìåòü, ñ âûñîêîé ñòåïåíüþ ; âåðîÿòíîñòè ìîæíî ïðåäïîëîæèòü, ÷òî ìû ; èìååì äåëî ñ îøèáêîé «ñðûâà ñòåêà», à ; âîçìîæíî, è ñ ïîïûòêîé àòàêè âàøåãî ; êîìïüþòåðà. ; ; Param#: ×åòûðå ïåðâûõ ïàðàìåòðà ôóíêöèè – èìåííî ; ñòîëüêî ïàðàìåòðîâ «Äîêòîð Âàòñîí» îòîáðàæàåò ; íà ýêðàíå. Ýòî äîñòàòî÷íî æåñòêîå îãðàíè÷åíèå – ; ìíîãèå ôóíêöèè èìåþò äåñÿòêè ïàðàìåòðîâ è ; ÷åòûðå ïàðàìåòðà åùå íè î ÷åì íå ãîâîðÿò; ; îäíàêî íåäîñòàþùèå ïàðàìåòðû ëåãêî âûòàùèòü ; èç êîïèè íåîáðàáîòàííîãî ñòåêà âðó÷íóþ – ; äîñòàòî÷íî ëèøü ïåðåéòè ïî óêàçàííîìó â ïîëå ; FramePtr àäðåñó. ; ; Func Name: Èìÿ ôóíêöèè (åñëè òîëüêî åãî âîçìîæíî ; ëåãêî âûòàùèòü è îïðåäåëèòü); ; ðåàëüíî îòîáðàæàåò ëèøü èìåíà ôóíêöèé, ; èìïîðòèðóåìûå èç äðóãèõ DLL, ïîñêîëüêó ; âñòðåòèòü êîììåð÷åñêóþ ïðîãðàììó, ; îòêîìïèëèðîâàííóþ âìåñòå ñ îòëàäî÷íîé ; èíôîðìàöèåé ïðàêòè÷åñêè íåðåàëüíî. ; 0012FFC0 77E87903 00000000 00000000 7FFDF000 C0000005 !<nosymbols> 0012FFF0 00000000 00401040 00000000 000000C8 00000100 ↵ kernel32!SetUnhandledExceptionFilter ; Ôóíêöèè ïåðå÷èñëÿþòñÿ â ïîðÿäêå èõ èñïîëíåíèÿ; ñàìîé ïîñëåäíåé ; èñïîëíÿëàñü kernel32!SetUnhandledExceptionFilter ôóíêöèÿ, ; îáðàáàòûâàþùàÿ äàííîå èñêëþ÷åíèå. *----> Êîïèÿ íåîáðàáîòàííîãî ñòåêà <----* ; Êîïèÿ íåîáðàáîòàííîãî ñòåêà ñîäåðæèò ñòåê òàêèì, êàêîé îí åñòü. ; Î÷åíü ïîìîãàåò ïðè îáíàðóæåíèè buffer overfull àòàê – ; âåñü shell-êîä, ïåðåäàííûé çëîóìûøëåííèêîì, áóäåò ðàñïå÷àòàí ; «Äîêòîðîì Âàòñîíîì», è âàì îñòàíåòñÿ âñåãî ëèøü îïîçíàòü åãî ; (ïîäðîáíåå îá ýòîì ðàññêàçûâàåòñÿ â ìîåé êíèãå "Òåõíèêà ; ñåòåâûõ àòàê") 0012ff70 00 00 00 00 00 00 00 00 - 39 10 40 00 00 00 00 00 ........9.@..... 0012ff80 64 00 00 00 f4 10 40 00 - 01 00 00 00 d0 0e 30 00 d.....@.......0. … 00130090 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................ 001300a0 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................ *----> Òàáëèöà ñèìâîëîâ <----* ; Òàáëèöà ñèìâîëîâ ñîäåðæèò èìåíà âñåõ çàãðóæåííûõ DLL âìåñòå ; ñ èìåíàìè èìïîðòèðóåìûõ ôóíêöèé. Èñïîëüçóÿ ýòè àäðåñà â ; êà÷åñòâå îòïðàâíîé òî÷êè, ìû áåç òðóäà ñìîæåì âîññòàíîâèòü ; «ïåðå÷åíü çàãðóæåííûõ DLL». ntdll.dll 77F81106 00000000 … 77FCEFB0 00000000
12
ZwAccessCheckByType fltused
kernel32.dll 77E81765 0000003d IsDebuggerPresent … 77EDBF7A 00000000 VerSetConditionMask ; ; Èòàê, âîçâðàùàåìñÿ ê òàáëèöå çàãðóæåííûõ DLL. ; (00400000 - 00406000) - ýòî, î÷åâèäíî, îáëàñòü ïàìÿòè, ; çàíÿòàÿ ñàìîé ïðîãðàììîé ; (77F80000 - 77FFA000) – ýòî KERNEL32.DLL ; (77E80000 - 77F37000) - ýòî NTDDL.DLL
Microsoft Visual Studio Debugger При установке среды разработки Microsoft Visual Studio она регистрирует свой отладчик основным отладчиком критических ошибок по умолчанию. Это простой в использовании, но функционально ущербный отладчик, не поддерживающий даже такой банальной операции, как поиск hex-последовательности в оперативной памяти. Единственная «вкусность», отличающая его от продвинутого во всех отношениях Microsoft Kernel Debugger – это возможность трассировки «упавших» процессов, выбросивших критическое исключение. В опытных руках отладчик Microsoft Visual Studio Debugger способен творить настоящие чудеса, и одно из таких чудес – это возобновление работы приложений, совершивших недопустимую операцию и при нормальном течении событий, аварийно завершаемых операционной системой без сохранения данных. В любом случае интерактивный отладчик (коим Microsoft Visual Studio Debugger и является) предоставляет намного более подробную информацию о сбое и значительно упрощает процесс выявления источников его возникновения. К сожалению, тесные рамки журнальной статьи не позволяют изложить всю методику поиска неисправностей целиком, и приходится ограничиваться лишь узким кругом наиболее интересных (и наименее известных!) вопросов (см. раздел «Обитатели сумеречной зоны, или из морга в реанимацию»). Для ручной установки Microsoft Visual Studio Debugger основным отладчиком критических ошибок добавьте в реестр следующие данные: Ëèñòèíã 3. Óñòàíîâêà Microsoft Visual Studio Debugger îñíîâíûì îòëàä÷èêîì êðèòè÷åñêèõ îøèáîê [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\ ↵ CurrentVersion\AeDebug] "Auto"="1" "Debugger"="\"C:\\Prg Files\\MS VS\\Common\\MSDev98\\Bin\\ ↵ msdev.exe\" -p %ld -e %ld" "UserDebuggerHotKey"=dword:00000000 Ëèñòèíã 4. Äåìîíñòðàöèîííàÿ ïðîãðàììà, âûçûâàþùàÿ ñîîáùåíèå î êðèòè÷åñêîé îøèáêå // Ôóíêöèÿ âîçâðàùàåò ñóììó n ñèìâîëîâ òèïà char. Åñëè åé // ïåðåäàòü null-pointer, îíà «óïàäåò», õîòÿ èñòî÷íèê îøèáêè // íå â íåé, à â àðãóìåíòàõ, ïåðåäàííûõ ìàòåðèíñêîé ôóíêöèåé. test(char *buf, int n) { int a, sum; // Çäåñü âîçáóæäàåòñÿ èñêëþ÷åíèå. for (a = 0; a < n; a++) sum += buf[a]; return sum; } main() { #define N 100 // Èíèöèàëèçèðóåì óêàçàòåëü íà áóôåð. char *buf = 0;
программирование // «Çàáûâàåì» âûäåëèòü ïàìÿòü, çäåñü îøèáêà. /* buf = malloc(100); */ // Ïåðåäàåì null-pointer íåêîòîðîé ôóíêöèè. test(buf, N); }
Обитатели сумеречной зоны, или из морга в реанимацию Хотите узнать, как заставить приложение продолжить нормальную работу после появления сообщения о критической ошибке? Это действительно очень актуально. Представьте, что рухнуло приложение, содержащее уникальные и еще не сохраненные данные. По минимуму их придется набивать заново, по максимуму – они потеряны для вас навсегда. На рынке имеется некоторое количество утилит, нацеленных на эту задачу (взять те же Norton Utilities), но их интеллектуальность оставляет желать лучшего и в среднем они срабатывают один раз из десяти. В то же самое время ручная реанимация программы воскрешает ее в 75-90% случаев. Строго говоря, гарантированно восстановить работоспособность обрушавшейся программы нельзя, равно как и невозможно выполнить откат тех действий, что предшествовали ее обрушению. В лучшем случае вам удастся сохранить свои данные на диск до того, как программа полностью потеряет нить управления и пойдет вразнос. Но и это неплохо! Существует по меньшей мере три различных способа реанимации: принудительный выход из функции, возбудившей исключение; «раскрутка» стека с передачей управления назад; передача управления на функцию обработки сообщений. Рассмотрим каждый из этих способов на примере приложения test.exe, копию которого вы можете скачать по адресу: www.samag.ru/sourse/test.zip. Забегая вперед, отметим, что реанимации поддаются лишь те сбои, что вызваны алгоритмическими, а не аппаратными ошибками (т.е. сбоем оборудования). Если информация, хранящаяся в оперативной памяти, оказалась искажена в результате физического дефекта последней, то восстановить работоспособность упавшего приложения скорее всего уже не удастся, хотя если сбой не затронул жизненно важные структуры данных, некоторая надежда на благополучный исход все-таки есть.
Ëèñòèíã 5. Îòëàä÷èê Microsoft Visual Studio Debugger äèçàññåìáëèðîâàë ôóíêöèþ, âîçáóäèâøóþ èñêëþ÷åíèå 0040135C 0040135D 00401361 00401362 00401366 00401368 00401369 0040136B 0040136D 0040136E 0040136F
push mov push movsx add inc cmp jl pop pop ret
esi esi,dword ptr [esp+8] edi edi,byte ptr [ecx+esi] eax,edi ecx ecx,edx 00401362 edi esi 8
Проанализировав причину возникновения исключения (функции передан указатель на невыделенную память), мы приходим к выводу, что заставить функцию продолжить свою работу невозможно, поскольку структура передаваемых данных нам не известна. Приходится прибегать к принудительному возврату в материнскую функцию, не забыв при этом установить флаг ошибки, сигнализируя программе, что текущая операция не была выполнена. К сожалению, никаких общепринятых флагов ошибок не существует, и различные функции используют различные соглашения. Чтобы выяснить, как обстоят дела в данном конкретном случае, мы должны дизассемблировать материнскую функцию и определить, какой именно код ошибки она ожидает. Переместив курсор в окно дампа, набьем в строке адреса название регистра указателя вершины стека – «ESP» и нажмем на <Enter>. Содержимое стека тут же предстанет перед нашими глазами: Ëèñòèíã 6. Ïîèñê àäðåñà âîçâðàòà èç òåêóùåé ôóíêöèè (âûäåëåí êðàñíûì øðèôòîì) 0012F488 0012F494 0012F4A0 0012F4AC 0012F4B8 0012F4C4 0012F4D0
0012FA64 00000000 FFFFFFFF 00000019 0012F4C0 006403C2 00640301
0012FA64 00000064 0012F4C4 00000000 0012FA64 002F5788 77E16383
004012FF 00403458 6C291CEA 6C32FAF0 01100059 00000000 004C1E20
Первые два двойных слова соответствуют машинным командам POP EDI/POP ESI и не представляют для нас совершенно никакого интереса. А вот следующее двойное слово содержит адрес выхода в материнскую процедуру (в приведенном выше листинге оно выделено красным шрифтом). Как раз оно-то нам и нужно! Нажимаем <Ctrl-D> и затем 0x4012FF, отладчик послушно отображает следующий дизассемблерный текст: Ëèñòèíã 7. Äèçàññåìáëåðíûé ëèñòèíã ìàòåðèíñêîé ôóíêöèè
Принудительный выход из функции Запускаем тестовую программу, набиваем в одном или нескольких окнах какой-нибудь текст, затем в меню «Help» выбираем пункт «About TestCEdit» и в появившемся диалоговом окне щелкаем по кнопке «make error». Программа выбрасывает критическую ошибку и, если мы нажмем на «ОК», все несохраненные данные необратимо погибнут, что никак не входит в наши планы. Однако при наличии предварительно установленного отладчика мы еще можем кое-что предпринять. Пусть для определенности это будет Microsoft Visual Studio Debugger. Нажимаем «Отмену», и отладчик немедленно дизассемблирует функцию, возбудившую исключение (см. листинг 5).
№12(13), декабрь 2003
004012FA 004012FF 00401302 00401304 00401305 00401309 0040130E 0040130F 00401315 00401318 0040131C 0040131E 00401320 00401321 00401323 00401328 00401329 0040132C 0040132C
call cmp je push lea push push call add lea push push push mov call pop add ret
00401350 eax,0FFh 0040132D eax eax, [esp+8] 405054h eax dword ptr ds:[4033B4h] esp, 0Ch ecx, [esp+4] 0 0 ecx ecx, esi 00401BC4 esi esp,64h
13
программирование 0040132D 0040132D 0040132F 00401331 00401336 00401338 0040133D 0040133E 00401341
push 0 ; ýòà âåòêà ïîëó÷àåò óïðàâëåíèå, åñëè Ôóíêöèÿ ; 401350h âåðíåò FFh push 0 push 405048h mov ecx,esi call 00401BC4 pop esi add esp,64h ret
Смотрите: если регистр EAX равен FFh, то материнская функция передает управление на ветку 40132Dh и, спустя несколько машинных команд, завершает свою работу, передавая бразды правления функции более высокого уровня. Напротив, если EAX != FFh, то его значение передается функции 4033B4h. Следовательно, мы можем предположить, что FFh – это флаг ошибки и есть. Возвращаемся в подопытную функцию, нажав <Ctrl-G> и «EIP», переходим в окно «Registers» и меняем значение EAX на FFh. Теперь необходимо найти подходящую точку возврата из функции. Просто перейти к машинной команде «RET» нельзя, поскольку перед выходом из функции следует в обязательном порядке сбалансировать стек, или нас выбросит неизвестно куда, и программа обрушится окончательно. В общем случае число PUSH-команд должно в точности соответствовать количеству POP (также учитывайте, что PUSH DWORD X эквивалентен SUB ESP, 4, а POP DWORD X – ADD ESP, 4). Проанализировав дизассемблерный листинг функции, мы приходим к выводу, что для достижения гармонии добра и зла мы должны стащить с вершины стека два двойных слова, соответствующие машинным командам 40135С:PUSH ESI и 401361:PUSH EDI. Это достигается передачей управления по адресу 40136Dh, где живут два добродушных POP, приводящие стек в равновесное состояние. Подводим сюда курсор и уверенным щелчком правой клавиши мыши вызываем контекстное меню, среди пунктов которого выбираем «Set Next Statement». Как вариант можно перейти в окно регистров и изменить значение EIP с 401362h на 40136Dh. Нажатием <F5> мы заставляем процессор продолжить выполнение программы и… о чудо! Она действительно продолжает свою работу (незлобное ругательство на ошибку последней операции – не в счет!). Несохраненные данные спасены!
Раскрутка стека Далеко не во всех случаях принудительный выход из функции оказывается возможным. Ряд критических сбоев затрагивает не одну, а сразу несколько вложенных функций, и тогда для реанимации программы мы должны совершить глубокий откат назад, продолжив выполнение программы с того места, где бы ее работоспособности ничто не угрожало. Точная глубина отката подбирается экспериментально и обычно составляет три-пять ступеней. Имейте в виду, что если вложенные функции модифицируют глобальные данные (например, данные «кучи»), то попытка отката может привести к полному краху отлаживаемой программы, поэтому требуемую глубину отката желательно угадать с первого раза, придерживаясь правила «лучше перебрать, чем недобрать». С другой сторо-
14
ны, чрезмерно глубокий откат ведет к потере всех несохраненных данных… Процедура отката состоит из трех шагов: построения дерева вызовов; определения координат стекового фрейма для каждого из них; восстановления регистрового контекста материнской функции. Хороший отладчик все это сделает за нас, и нам останется лишь записать в регистры EIP и ESP соответствующие значения. К сожалению, отладчик Microsoft Visual Studio Debugger к хорошим отладчикам не относится. Он довольно посредственно трассирует стек, пропуская FPOфункции (Frame Point Omission – функции с оптимизированным фреймом) и не сообщает координат стекового фрейма, «благодаря» чему самую трудоемкую часть работы нам приходится выполнять самостоятельно. Впрочем, даже такой стек вызовов все же лучше, чем совсем ничего. Раскручивая его вручную, мы будем отталкиваться от того, что координаты фрейма естественным образом определяются по адресу возврата. Допустим, содержимое окна «Call Stack» выглядит так: Ëèñòèíã 8. Ñîäåðæèìîå îêíà Call Stacks îòëàä÷èêà Microsoft Visual Studio Debugger TESTCEDIT! 00401362() MFC42! 6c2922ae() MFC42! 6c298fc5() MFC42! 6c292976() MFC42! 6c291dcc() MFC42! 6c291cea() MFC42! 6c291c73() MFC42! 6c291bfb() MFC42! 6c291bba()
Попробуем найти в стеке адреса 6C2922AEh и 6C298FC5h, соответствующие двум последним ступеням исполнения. Нажимаем <ATL-6> для перехода в окно дампа и, воспользовавшись горячей комбинацией клавиш <Ctrl-G> в качестве базового адреса отображения, выбираем «ESP». Прокручивая окно дампа вниз, мы обнаруживаем оба адреса возврата (в приведенном ниже листинге они выделены рамкой): Ëèñòèíã 9. Ñîäåðæèìîå ñòåêà ïîñëå ðàñêðóòêè 0012F488 0012FA64 0012FA64 004012FF ↵ <-- 0040136F:ret 8 ïåðâûé àäðåñ âîçâðàòà 0012F494 00000000 00000064 00403458 ↵ <-- 00401328:pop esi 0012F4A0 FFFFFFFF 0012F4C4 6C291CEA 0012F4AC 00000019 00000000 6C32FAF0 0012F4B8 0012F4C0 0012FA64 01100059 0012F4C4 00320774 002F5788 00000000 0012F4D0 00320701 77E16383 004C1E20 0012F4DC 00320774 002F5788 00000000 0012F4E8 000003E8 0012FA64 004F8CD8 0012F4F4 0012F4DC 002F5788 0012F560 0012F500 77E61D49 6C2923D8 00403458 ↵ <-- 0040132C:ret; 0012F50C 00000111 0012F540 6C2922AE ↵ <--6C29237E:pop ebx/pop ebp/ret 1Ch 0012F518 0012FA64 000003E8 00000000 0012F518 0012FA64 000003E8 00000000 0012F524 004012F0 00000000 0000000C 0012F530 00000000 00000000 0012FA64 0012F53C 000003E8 0012F564 6C298FC5 0012F548 000003E8 00000000 00000000 0012F554 00000000 000003E8 0012FA64
программирование Ячейки памяти, лежащие выше адресов возврата, представляют собой значения регистров, сохраненные в стеке при входе в функцию и восстанавливаемые при ее завершении. Ячейки памяти, лежащие ниже адресов возврата, оккупированы аргументами функции (если, конечно, у функции есть аргументы), или же принадлежат локальным переменным материнской функции, если дочерняя функция не принимает никаких аргументов. Возвращаясь к листингу 5, отметим, что два двойных слова, лежащие на верхушке стека, соответствуют машинным командам POP EDI и POP ESI, а следующий за ними адрес – 4012FFh – это тот самый адрес, управление которому передается командой 40136Fh:RET 8. Для продолжения раскрутки стека мы должны дизассемблировать код по этому адресу: Ëèñòèíã 10. Äèçàññåìáëåðíûé ëèñòèíã ïðàìàòåðèíñêîé ôóíêöèè («áàáóøêè») 004012FA 004012FF 00401302 00401304 00401305 00401309 0040130E 0040130F 00401315 00401318 0040131C 0040131E 00401320 00401321 00401323 00401328 00401329 0040132C
call cmp je push lea push push call add lea push push push mov call pop add ret
00401350 eax,0FFh 0040132D eax eax,[esp+8] 405054h eax dword ptr ds:[4033B4h] esp,0Ch ecx,[esp+4] 0 0 ecx ecx,esi 00401BC4 esi esp,64h ; SS:[ESP] = 6C2923D8
Прокручивая экран вниз, мы замечаем инструкцию ADD ESP, 64, закрывающую текущий кадр стека. Еще восемь байт снимает инструкция 40136Fh:RET 8 и четыре байта оттягивает на себя 401328:POP ESI. Таким образом, позиция адреса возврата в стеке равна: current_ESP + 64h + 8 + 4 == 70h. Спускаемся на 70h байт ниже и видим:
Ëèñòèíã 13. Ñîäåðæèìîå ðåãèñòðîâ, ðàíåå ñîõðàíåííûõ â ñòåêå âìåñòå ñ àäðåñîì âîçâðàòà 0012F500 77E61D49 6C2923D8 00403458 <-- 6C29237D:pop esi 0012F50C 00000111 0012F540 6C2922AE <-- 6C29237E:pop ebx ↵ /pop ebp/ret 1Ch
Как вариант можно переместить регистр EIP на адрес 6C29237Dh, а регистр ESP на адрес 12F508h, после чего нажать на <F5> для продолжения выполнения программы. И этот прием действительно срабатывает! Причем реанимированная программа уже не ругается на ошибку последней операции (как это было при восстановлении путем принудительного выхода из функции), а просто ее не выполняет. Красота!
Передача управления на функцию обработки сообщений Двум предыдущим способам «реанимации» приложений присущи серьезные ограничения и недостатки. При тяжелых разрушениях стека, вызванных атаками типа buffer overfull или же просто алгоритмическими ошибками, содержимое важнейших регистров процессора окажется искажено, и мы уже не сможем ни совершить откат (стек утерян), ни выйти из текущей функции (EIP смотрит в космос). В консольных приложениях в такой ситуации действительно очень мало что можно сделать… Вот GUI – другое дело! Концепция событийно ориентированной архитектуры наделяет всякое оконное приложение определенными серверными функциями. Даже если текущий контекст выполнения необратимо утерян, мы можем передать управление на цикл извлечения и диспетчеризации сообщений, заставляя программу продолжить обработку действий пользователя. Классический цикл обработки сообщений выглядит так: Ëèñòèíã 14. Êëàññè÷åñêèé öèêë îáðàáîòêè ñîîáùåíèé while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
Ëèñòèíã 11. Àäðåñ âîçâðàòà èç ïðàìàòåðèíñêîé ôóíêöèè 0012F500 77E61D49 6C2923D8 00403458 <-- 00401328:POP ESI/ret;
Первое двойное слово – это значение регистра ESI, который нам предстоит вручную восстановить; второе – адрес возврата из функции. Нажатием <Ctrl-G>, «0x6C2923D8» мы продолжаем раскручивать стек: Ëèñòèíã 12. Äèçàññåìáëåðíûé ëèñòèíã ïðàïðàìàòåðèíñêîé ôóíêöèè 6C2923D8 … 6C29237B 6C29237D 6C29237E 6C29237F 6C292380
jmp
6C29237B
mov pop pop pop ret
eax,ebx esi ebx ebp 1Ch
Вот мы и добрались до восстановления регистров! Сместившись на одно двойное слово вправо (оно только что было вытолкнуто из стека командой RET), переходим в окно «Registers» и восстанавливаем регистры ESI, EBX, EBP, извлекая сохраненные значения из стека:
№12(13), декабрь 2003
Все, что нам нужно, – это передать управление на цикл while, даже не заботясь о настройке кадра стека, поскольку оптимизированные программы (а таковых большинство) адресуют свои локальные переменные не через EBP, а непосредственно через сам ESP. Конечно, при обращении к переменной msg, функция угробит содержимое стека, лежащее ниже его вершины, но это уже не важно. Правда, при выходе из приложения оно упадет окончательно (ведь вместо адреса возврата из функции обработки сообщений машинная команда RET обнаружит на вершине стека неизвестно что), но это произойдет после сохранения всех данных, и потому никакой угрозы не несет. Исключение составляют приложения, «забывающие» закрыть все открытые файлы и перекладывающие эту работу на плечи функции ExitProcess. Что ж! Можно так подправить адрес возврата, чтобы он указывал на ExitProcess! Давайте создадим простейшее Windows-приложение и поэкспериментируем с ним. Запустив Microsoft Visual
15
программирование Studio выберем «New → Project → Win32 Application» и там – «Typical Hello, World application». Добавим новый пункт меню, а в нем: char *p; *p = 0; и откомпилируем этот проект с отладочной информацией. Роняем приложение на пол и, запустив отладчик, подгоняем мышь к первой строке цикла обработки сообщений и в появившемся контекстном меню находим пункт «Set Next Statement». Нажимаем <F5> для возобновления работы программы и… она действительно возобновляет свою работу! А теперь откомпилируем наш проект в чистовом варианте (т.е. без отладочной информации) и попробуем реанимировать приложение в голом машинном коде. Пользуясь тем обстоятельством, что Windows – это действительно многозадачная среда, в которой крушение одного процесса не мешает работе всех остальных, запустим свой любимый дизассемблер (например IDA PRO) и проанализируем таблицу импорта отлаживаемой программы (вообще-то это может сделать и бесплатно распространяемый dumpbin, но его отчет не так нагляден). Целью нашего поиска будут функции TranslateMessage/ DispatchMessage и перекрестные ссылки, ведущие к циклу выборки сообщений. Ëèñòèíã 15. Ïîèñê ôóíêöèé TranslateMessage/DispatchMessage â òàáëèöå èìïîðòà .idata:004040E0 ; BOOL __stdcall ↵ TranslateMessage(const MSG *lpMsg) .idata:004040E0 extrn TranslateMessage:dword ; DATA ↵ XREF: _WinMain@16+71?r .idata:004040E0 ; _WinMain@16+8D?r .idata:004040E4 ; LONG __stdcall ↵ DispatchMessageA(const MSG *lpMsg) .idata:004040E4 extrn DispatchMessageA:dword ; DATA ↵ XREF: _WinMain@16+94?r .idata:004040E8
С функцией DispatchMessage связана всего лишь одна перекрестная ссылка, со всей очевидностью ведущая к искомому циклу обработки сообщений, дизассемблерный код которого выглядит так: Ëèñòèíã 16. Äèçàññåìáëåðíûé ëèñòèíã ôóíêöèè îáðàáîòêè ñîîáùåíèé .text:00401050 .text:00401050 .text:00401050 .text:00401056 .text:00401058 .text:0040105A .text:0040105A .text:0040105A .text:0040105A .text:0040105A .text:0040105A .text:0040105A .text:0040105E .text:00401060 .text:00401061 .text:00401063 .text:0040106 .text:00401063 .text:00401065 .text:00401067 .text:00401067
mov edi, ds:GetMessageA ; ïåðâûé âûçîâ GetMessageA (ýòî åùå ; íå öèêë, ýòî òîëüêî åãî ïðåääâåðüå)
; ; ; ; ; ; ;
push 0 ; wMsgFilterMax push 0 ; wMsgFilterMin lea ecx, [esp+2Ch+Msg] ECX óêàçûâàåò íà îáëàñòü ïàìÿòè, ÷åðåç êîòîðóþ GetMessageA ñòàíåò âîçâðàùàòü ñîîáùåíèå. Òåêóùåå çíà÷åíèå ESP ìîæåò áûòü ëþáûì, ãëàâíîå, ÷òîáû îíî óêàçûâàëî íà äåéñòâèòåëüíóþ îáëàñòü ïàìÿòè (ñì. êàðòó ïàìÿòè, åñëè çíà÷åíèå ESP îêàçàëîñü èñêàæåíî íàñòîëüêî, ÷òî âûâåëî åãî â «êîñìîñ»)
push 0 ; hWnd push ecx ; lpMsg mov esi, eax call edi ; GetMessageA ; âûçûâàåì GetMessageA test jz ; ïðîâåðêà íà ; ñîîáùåíèé â
.text:00401067 … .text:00401077 loc_401077:
16
eax, eax short loc_4010AD íàëè÷èå íåîáðàáîòàííûõ î÷åðåäè ;CODE XREF: _WinMain@16+A9?j
.text:00401077 .text:00401077 .text:00401077 .text:0040107B .text:0040107B .text:0040107B .text:0040107F .text:00401080 .text:00401081 .text:00401082 .text:00401082 .text:00401082 .text:00401084 .text:00401086 .text:00401086 .text:00401086 .text:00401088 .text:0040108C .text:0040108D .text:0040108D
; íà÷àëî öèêëà îáðàáîòêè ñîîáùåíèé mov eax, lea edx, ; EDX óêàçûâàåò íà ; èñïîëüçóåìóþ äëÿ
[esp+2Ch+Msg.hwnd] [esp+2Ch+Msg] îáëàñòü ïàìÿòè, ïåðåäà÷è ñîîáùåíèé
push edx ; lpMsg push esi ; hAccTable push eax ; hWnd call ebx ; TranslateAcceleratorA ; âûçûâàåì ôóíêöèþ TranslateAcceleratorA test eax, eax jnz short loc_40109A ; ïðîâåðêà íà íàëè÷èå â î÷åðåäè ; íåîáðàáîòàííûõ ñîîáùåíèé lea ecx, [esp+2Ch+Msg] push ecx ; lpMsg call ebp ; TranslateMessage ; âûçûâàåì ôóíêöèþ TranslateMessage, åñëè ; åñòü ÷òî òðàíñëèðîâàòü
.text:0040108D .text:0040108F lea edx, [esp+2Ch+Msg] .text:00401093 push edx ; lpMsg .text:00401094 call ds:DispatchMessageA .text:00401094 ; äèñïåò÷åðèçóåì ñîîáùåíèå .text:0040109A .text:0040109A loc_40109A: ; CODE XREF: _WinMain@16+86?j .text:0040109A push 0 ; wMsgFilterMax .text:0040109C push 0 ; wMsgFilterMin .text:0040109E lea eax, [esp+34h+Msg] .text:004010A2 push 0 ; hWnd .text:004010A4 push eax ; lpMsg .text:004010A5 call edi ; GetMessageA .text:004010A5 ; ÷èòàåì î÷åðåäíîå ñîîáùåíèå èç î÷åðåäè .text:004010A5 .text:004010A7 test eax, eax .text:004010A9 jnz short loc_401077 .text:004010A9 ; âðàùàåì öèêë îáðàáîòêè ñîîáùåíèé .text:004010A9 .text:004010AB pop ebp .text:004010AC pop ebx .text:004010AD .text:004010AD loc_4010AD: ; CODE XREF: _WinMain@16+67?j .text:004010AD mov eax, [esp+24h+Msg.wParam] .text:004010B1 pop edi .text:004010B2 pop esi .text:004010B3 add esp, 1Ch .text:004010B6 retn 10h .text:004010B6 _WinMain@16 endp
Мы видим, что цикл обработки сообщений начинается с адреса 401050h и именно на этот адрес следует передать управление, чтобы возобновить работу упавшей программы. Пробуем сделать это и… программа работает! Разумеется, настоящее приложение оживить намного сложнее, поскольку цикл обработки сообщений в нем рассредоточен по большому количеству функций, отождествить которые при беглом дизассемблировании невозможно. Тем не менее, приложения, построенные на основе общедоступных библиотек (например MFC, OVL) обладают вполне предсказуемой архитектурой, и реанимировать их вполне возможно. Рассмотрим, как устроен цикл обработки сообщений в MFC. Большую часть своего времени исполнения MFC-приложения проводят внутри функции CWinThread::Run(void), которая периодически опрашивает очередь на предмет поступления свежих сообщений и рассылает их соответствующим обработчикам. Если один из обработчиков споткнулся и довел систему до критической ошибки, выполнение программы может быть продолжено в функции Run. В этом-то и заключается ее главная прелесть! Функция не имеет явных аргументов, но принимает скрытый аргумент this, указывающей на экземпляр клас-
программирование са CWinThread или производный от него класс, без которого функция просто не сможет работать. К счастью, таблицы виртуальных методов класса CWinThread содержат достаточно количество «родимых пятен», чтобы указатель this можно было воссоздать вручную. Загрузим функцию Run в дизассемблер и отметим все обращения к таблице виртуальных методов, адресуемой через регистр ECX. Ëèñòèíã 17. Äèçàññåìáëåðíûé ëèñòèíã ôóíêöèè Run (ôðàãìåíò) .text:6C29919D n2k_Trasnlate_main: ; CODE XREF: MFC42_5715+1F?j .text:6C29919D ; MFC42_5715+67?j ... .text:6C29919D mov eax, [esi] .text:6C29919F mov ecx, esi .text:6C2991A1 call dword ptr [eax+64h] ; CWinThread::PumpMessage(void) .text:6C2991A4 test eax, eax .text:6C2991A6 jz short loc_6C2991DA .text:6C2991A8 mov eax, [esi] .text:6C2991AA lea ebp, [esi+34h] .text:6C2991AD push ebp .text:6C2991AE mov ecx, esi .text:6C2991B0 call dword ptr [eax+6Ch] ; CWinThread::IsIdleMessage(MSG*) .text:6C2991B3 test eax, eax .text:6C2991B5 jz short loc_6C2991BE .text:6C2991B7 push 1 .text:6C2991B9 mov [esp+14h], ebx .text:6C2991BD pop edi .text:6C2991BE .text:6C2991BE loc_6C2991BE: ; CODE XREF: MFC42_5715+51?j .text:6C2991BE push ebx ; wRemoveMsg .text:6C2991BF push ebx ; wMsgFilterMax .text:6C2991C0 push ebx ; wMsgFilterMin .text:6C2991C1 push ebx ; hWnd .text:6C2991C2 push ebp ; lpMsg .text:6C2991C3 call ds:PeekMessageA .text:6C2991C9 test eax, eax .text:6C2991CB jnz short n2k_Trasnlate_main .text:6C2991CD
Таким образом, функция Run ожидает получить указатель на двойное слово, указывающее на таблицу виртуальных методов, 0x19 и 0x1B элементы которой представляют собой функции PumpMessage и IsIdleMessage соответственно (или переходники к ним). Адреса импортируемых функций, если только динамическая библиотека не была перемещена, можно узнать в том же дизассемблере; в противном случае, следует отталкиваться от базового адреса модуля, отображаемого отладчиком по команде «Modules». При условии, что эти две функции не были перекрыты программистом, поиск нужной нам виртуальной таблицы не составит никакого труда. По непонятным причинам библиотека MFC42.DLL не экспортирует символьных имен функций, и эту информацию нам приходится добывать самостоятельно. Обработав библиотеку MFC42.LIB утилитой dumpbin, запущенной с ключом «/ARCH», мы определим ординалы обеих функций (ординал PumpMessage – 5307, а IsIdleMessage – 4079). Остается найти эти значения в экспорте библиотеки MFC42.DLL (dumpbin /EXPORTS mfc42.dll > mfc42.txt), из чего мы узнаем что адрес функции PumpMessage: 6C291194h, а IsIdleMessage – 6С292583h. Теперь мы должны найти указатели на функции PumpMessage/IsIdleMessage в памяти, а точнее – в секции данных, базовый адрес которой содержится в заголовке PE-файла, только помните, что в x86-процессорах
№12(13), декабрь 2003
наименее значимый байт располагается по меньшему адресу, т.е. все числа записываются задом наперед (к сожалению, отладчик Microsoft Visual Studio Debugger не поддерживает операцию поиска в памяти, и нам приходится действовать обходным путем – копировать содержимое дампа в буфер обмена, вставлять его в текстовой файл и, нажав <F7>, искать адреса уже там). Долго ли, коротко ли, но интересующие нас указатели обнаруживаются по адресам 403044h/40304Сh (естественно, у вас эти адреса могут быть и другими). Причем обратите внимание: расстояние между указателями в точности равно расстоянию между указателями на [EAX + 64h] и [EAX + 6Ch], а очередность их размещения в памяти обратна порядку объявления виртуальных методов. Это хороший признак, и мы, скорее всего, находимся на правильном пути: Ëèñòèíã 18. Àäðåñà ôóíêöèé IsIdleMessage/PumpMessage, íàéäåííûå â ñåêöèè äàííûõ ; IsIdleMessage/PumpMessage 00403044 6C2911D4 6C292583 6C291194 00403050 6C2913D0 6C299144 6C297129 0040305C 6C297129 6C297129 6C291A47
Указатели, указывающие на адреса 403048h/40304Ch, очевидно, и будут кандидатами в члены искомой таблицы виртуальных методов класса CWinThread. Расширив сферу поиска всем адресным пространством отлаживаемого процесса, мы обнаруживаем два следующих переходника: Ëèñòèíã 19. Ïåðåõîäíèêè ê ôóíêöèÿì IsIdleMessage/PumpMessage, íàéäåííûå òàì æå 00401A20 00401A26 00401A2C
jmp jmp jmp
dword ptr ds:[403044h] ; IsIdleMessage dword ptr ds:[403048h] ; dword ptr ds:[40304Ch] ; PumpMessage
Ага, уже теплее! Мы нашли не сами виртуальные функции, но переходники к ним. Раскручивая этот запутанный клубок, попробуем отыскать ссылки на 401A26h/ 401A2Ch, которые передают управление на приведенный выше код: Ëèñòèíã 20. Âèðòóàëüíàÿ òàáëèöà êëàññà CWinThread 00403490 0040349C 004034A8 004034B4 004034C0 004034CC 004034D8 004034E4 004034F0 004034FC
00401A9E 00401040 004015F0 <-- 0x0, 0x1, 0x2 ýëåìåíòû 00401390 004015F0 00401A98 <-- 0x3, 0x4, 0x5 ýëåìåíòû 00401A92 00401A8C 00401A86 <-- 0x6, 0x7, 0x8 ýëåìåíòû 00401A80 00401A7A 00401A74 <-- 0x9, 0xA, 0xB ýëåìåíòû 00401010 00401A6E 00401A68 <-- 0xC, 0xD, 0xE ýëåìåíòû 00401A62 00401A5C 00401A56 <-- 0xF, 0x10, 0x11 ýëåìåíòû 00401A50 00401A4A 00401A44 <-- 0x12, 0x13, 0x14 ýëåìåíòû 00401A3E 004010B0 00401A38 <-- 0x15, 0x16, 0x17 ýëåìåíòû 00401A32 00401A2C 00401A26 <-- 0x18, 0x19, 0x1A ýëåìåíòû (PumpMessage) 00401A20 00401A1A 00401A14 <-- 0x1B, 0x1C, 0x1D ýëåìåíòû (IsIdleMessage)
Даже неопытный исследователь программ распознает в этой структуре данных таблицу виртуальных функций.
17
программирование Указатели на переходники к PumpMessage/IsIdleMessage разделяются ровно одним элементом, как того и требуют условия задачи. Предположим, что это виртуальная таблица, которая нам и нужна. Для проверки этого предположения отсчитаем 0x19 элементов верх от 4034F4h и попытаемся найти указатель, ссылающийся на ее начало. Если повезет и он окажется экземпляром класса CwinThread, тогда программа сможет корректно продолжить свою работу: Ëèñòèíã 21. Ýêçåìïëÿð êëàññà CWinThread, âðó÷íóþ íàéäåííûé íàìè â ïàìÿòè 004050B8 004050C4
00403490 00000001 00000000 00000000 00000000 00000001
Действительно, в памяти обнаруживается нечто похожее. Записываем в регистр ECX значение 4050B8h, находим в памяти функцию Run (как уже говорилось, если только она не была перекрыта, ее адрес – 6C299164h – известен). Нажимаем <Ctrl-G>, затем «0x6C299164», и в контекстном меню, вызванном правой клавишей мыши, выбираем «Set Next Statement». Программа, отделавшись легким испугом, продолжает свое исполнение, ну а мы на радостях идем пить пиво (кофе, квас, чай – по вкусу). Аналогичным путем можно вернуть к жизни и зависшие приложения, потерявшие нить управления и не реагирующие ни на мышь, ни на клавиатуру.
Как подключить дамп памяти …в отделе программ весь пол был усеян дырочками от перфокарт и какие-то мужики ползали по раскатанной по полу 20-метровой распечатке аварийного дампа памяти с целью обнаружения ошибки в распределителе памяти ОС-360. К президенту подошел начальник отдела и сообщил, что есть надежда сделать это еще к обеду. Ю.Антонов «Юность Гейтса»
Дамп памяти (memory dump, также называемый корой [от английского core – сердцевина], crash- или аварийным дампом), сброшенный системой при возникновении критической ошибки – не самое убедительное средство для выявления причин катастрофы, но ничего другого в руках администратора зачастую просто не бывает. Последний вздох операционной системы, похожий на дурно пахнущую навозную кучу, из которой высовывается чей-то наполовину разложившийся труп, мгновенным снимком запечатленный в момент неустранимого сбоя, – вот что такое дамп памяти! Копание в нем вряд ли доставит вам удовольствие. Не исключено, что истинного виновника краха системы вообще не удастся найти. Допустим, некий некорректно работающий драйвер вторгся в область памяти, принадлежащую другому драйверу, и наглым образом затер критические структуры данных, сделав из чисел винегрет. К тому моменту, когда драйвер-жертва пойдет вразнос, драйвер-хищник может быть вообще выгружен из системы, и определить его причастность к крушению системы по одному лишь дампу практически нереально. Тем не менее, полностью игнорировать факт существования дампа, право же, не стоит. В конце концов, до возникновения интерактивных отладчиков ошибки в программах приходилось искать именно так. Избалованность современных программистов визуальными средствами ана-
18
лиза, увы, не добавляет им уверенности в тех ситуациях, когда неумолимая энтропия оставляет их со своими проблемами один на один. Но довольно лирики. Переходим к делу, расписывая каждое действие по шагам. Первым делом необходимо войти в конфигурацию системы («Панель управления» → «Система»/«Control Panel» → «System») и убедиться, что настройки дампа соответствуют предъявляемым к ним требованиям («Дополнительно» → «Загрузка и восстановление» → «Отказ системы»/«Startup/Shutdown» → «Recovery» в Windows 2000 RUS и Windows NT 4.0 ENG соответственно). Операционная система Windows 2000 поддерживает три разновидности дампов памяти: малый дамп памяти (small memory dump), дамп памяти ядра (kernel memory dump) и полный дамп памяти (complete dump memory). Для изменения настроек дампа вы должны иметь права администратора. Малый дамп памяти занимает всего лишь 64 Кб (а отнюдь не 2 Мб, как утверждает контекстная помощь) и включает в себя: копию голубого экрана смерти; перечень загруженных драйверов; контекст обрушившегося процесса со всеми его потоками; первые 16 Кб содержимого ядерного стека обрушившегося потока. Разочаровывающие малоинформативные сведения! Непосредственный анализ дампа дает нам лишь адрес возникновения ошибки и имя драйвера, к которому этот адрес принадлежит. При условии, что конфигурация системы не была изменена после возникновения сбоя, мы можем загрузить отладчик и дизассемблировать подозреваемый драйвер, но это мало что даст. Ведь содержимое сегмента данных на момент возникновения сбоя нам неизвестно, более того, мы не можем утверждать, что видим те же самые машинные команды, что вызвали сбой. Поэтому малый дамп памяти полезен лишь тем администраторам, которым достаточно одного лишь имени нестабильного драйвера. Как показывает практика, в подавляющем большинстве случаев этой информации оказывается вполне достаточно. Разработчикам драйвера отсылается гневный бан-рапорт (вместе с дампом!), а сам драйвер тем временем заменяется другим – более новым и надежным. По умолчанию малый дамп памяти записывается в директорию %SystemRoot%\Minidump, где ему присваивается имя «Mini», дата записи дампа и порядковый номер сбоя на данный день. Например «Mini11070169.dmp» – 69 дамп системы от 07 ноября 2001 года (не пугайтесь! это просто я отлаживал драйвера). Дамп памяти ядра содержит намного более полную информацию о сбое и включает в себя всю память, выделенную ядром и его компонентами (драйверами, уровнем абстракции от оборудования и т. д.), а также копию экрана смерти. Размер дампа памяти ядра зависит от количества установленных драйверов и варьируется от системы к системе. Контекстная помощь утверждает, что эта величина составляет от 50 до 800 Мб. Ну, на счет 800 Мб авторы явно загнули, и объем в 50-100 Мб выглядит бо-
программирование лее вероятным (техническая документация на систему сообщает, что ориентировочный размер дампа ядра составляет треть объема физической оперативной памяти, установленной на системе). Это наилучший компромисс между накладными расходами на дисковое пространство, скоростью сброса дампа и информативностью последнего. Весь джентльменский минимум информации в вашем распоряжении. Практически все типовые ошибки драйверов и прочих ядерных компонентов могут быть локализованы с точностью до байта, включая и те, что вызваны физическим сбоем аппаратуры (правда, для этого вы должны иметь некоторый патологоанатомический опыт исследования трупных дампов системы). По умолчанию дамп памяти ядра записывается в файл %SystemRoot%\Memory.dmp, затирая или не затирая (в зависимости от текущих настроек «Системы») предыдущий дамп. Полный дамп памяти включает в себя все содержимое физической памяти компьютера, занятое как прикладными, так и ядерными компонентами. Полный дамп памяти оказывается особенно полезным при отладке ASPI/SPTI приложений, которые в силу своей специфики могут уронить ядро даже с прикладного уровня. Несмотря на довольно большой размер, равный размеру оперативной памяти, полный дамп остается наиболее любимым дампом всех системных программистов (системные же администраторы в своей массе предпочитают малый дамп). Это не покажется удивительным, если вспомнить, что объемы жестких дисков давно перевалили за отметку 100 Гб, а оплата труда системных программистов за последние несколько лет даже несколько возросла. Лучше иметь невостребованный полный дамп под рукой, чем кусать локти при его отсутствии. По умолчанию полный дамп памяти записывается в файл %SystemRoot%\Memory.dmp, затирая или не затирая (в зависимости от текущих настроек «Системы») предыдущий дамп. Выбрав предпочтительный тип дампа, давайте совершим учебный урон системы, отрабатывая методику его анализа в полевых условиях. Для этого нам понадобится: Комплект разработчика драйверов (Driver Development Kit или сокращенно DDK), бесплатно распространяемый фирмой Microsoft и содержащий в себе подробную техническую документацию по ядру системы; несколько компиляторов Си/Си++ и ассемблера, а также достаточно продвинутые средства анализа дампа памяти. Драйвер W2K_KILL.SYS или любой другой драйверубийца операционной системы, например BDOS.EXE от Марка Русиновича, позволяющий получить дамп в любое удобное для нас время, не дожидаясь возникновения критической ошибки (бесплатную копию программы можно скачать с адреса http://www.sysinternals.com). Файлы символьных идентификаторов (symbol files), необходимые отладчикам ядра для его нормального функционирования и делающие дизассемблерный код более наглядным. Файлы символьных идентификаторов входят в состав «зеленого» набора MSDN, но, в принципе, без них можно и обойтись, однако переменная окружения _NT_SYMBOL_PATH по любому должна быть определена, иначе отладчик i386kd.exe работать не будет.
№12(13), декабрь 2003
Одна или несколько книжек, описывающих архитектуру ядра системы. Очень хороша в этом смысле «Внутреннее устройство Windows 2000» Марка Руссиновича и Дэвида Соломона, интересная как системным программистам, так и администраторам. Итак, установив DDK на свой компьютер и завершив все приложения, запускаем драйвер-убийцу и… под скрипящий звук записывающегося дампа, система немедленно выбрасывает голубой экран смерти, кратко информирующий нас о причинах сбоя (см. рис. 5).
Ðèñóíîê 5. Ãîëóáîé ýêðàí ñìåðòè (BSOD – Blue Screen Of Death), ñâèäåòåëüñòâóþùèé î âîçíèêíîâåíèè íåóñòðàíèìîãî ñáîÿ ñèñòåìû ñ êðàòêîé èíôîðìàöèåé î íåì
Для большинства администраторов голубой экран смерти означает лишь одно – системе поплохело настолько, что она предпочла смерть позору неустойчивого функционирования. Что же до таинственных письмен – они остаются сплошной загадкой. Но только не для настоящих профессионалов! Мы начнем с левого верхнего угла экрана и, зигзагами спускаясь вниз, трассируем все надписи по порядку. «*** STOP:» буквально означает «останов [системы]» и не несет в себе никакой дополнительной информации; «0x0000001E» представляет собой Bug Check-код, содержащий категорию сбоя. Расшифровку Bug Checkкодов можно найти в DDK. В данном случае это 0x1E – KMODE_EXEPTION_NOT_HALTED, о чем и свидетельствует символьное имя, расположенное строкой ниже. Краткое объяснение некоторых, наиболее популярных Bug Check-кодов приведено в таблице 1. Полноту фирменной документации она, разумеется, не заменяет, но некоторое представление о целесообразности скачивания 70 Мб DDK все-таки дает; арабская вязь в круглых скобках – это четыре Bug Check-параметра, физический смысл которых зависит от конкретного Bug Check-кода и вне его контекста теряет всякий смысл; применительно к KMODE_EXEPTION_NOT_HALTED – первый Bug Checkпараметр содержит номер возбужденного исключения. Судя по таблице 1, это – STATUS_ACCESS_VIOLATION – доступ к запрещенному адресу памяти – и четвертый Bug Check-параметр указывает, какой именно. В данном случае он равен нулю, следовательно, некоторая машинная инструкция попыталась совершить обращение по null-pointer соответствующему инициализированному указателю, ссылающемуся на невыделенный регион памяти. Ее адрес содержится во втором Bug Check-параметре. Третий Bug Check-параметр в данном конкретном случае не определен; «*** Address 0xBE80B00» – это и есть тот адрес, по которому произошел сбой. В данном случае он идентичен второму Bug Check-параметру, однако так бывает далеко не всегда (Bug Check-коды собственно и не подряжались хранить чьи-либо адреса);
19
программирование «base at 0xBE80A00» – содержит базовый адрес загрузки модуля нарушителя системного порядка, по которому легко установить паспортные данные самого этого модуля (внимание: далеко не во всех случаях правильное определение базового адреса вообще возможно). Воспользовавшись любым подходящим отладчиком (например, soft-ice от Нумега или i386kd от Microsoft), введем команду, распечатывающую перечень загруженных драйверов с их краткими характеристиками (в i386kd это осуществляется командой «!drivers»). Как одним из вариантов можно воспользоваться утилитой drivers.exe, входящей в NTDDK. Но какой бы вы путь ни избрали, результат будет приблизительно следующим:
Обратите внимание на выделенную жирным цветом строку с именем «w2k_kill.sys», найденную по ее базовому адресу 0xBE80A00. Это и есть тот самый драйвер, который нам нужен! А впрочем, этого можно и не делать, поскольку имя «неправильного» драйвера и без того присутствует на голубом экране; две нижние строки отражают прогресс сброса дампа на диск, развлекая администратора чередой быстро меняющихся циферок на это время. Òàáëèöà 1.
Восстановление системы после критического сбоя Неестественное, почти половое влечение к кнопке F8 появилось в Кролике совершенно не внезапно. Щербаков Андрей «14400 бод и 19200 юзеров, и те же самые все-все-все...»
Операционные системы семейства NT достаточно безболезненно переносят критические сбои, даже если те произошли в самый неудобный момент времени (например, в период дефрагментации диска). Отказоустойчивый драйвер файловой системы все сделает сам (хотя запустить ChkDsk все же не помешает). Если был выбран «полный дамп памяти» или «дамп памяти ядра», то при следующей успешной загрузке системы жесткий диск будет долго молотить головкой, даже если к нему и не происходит никаких обращений. Не пугайтесь! Просто Windows перемещает дамп из виртуальной памяти на место его постоянного проживания. Запустив «Диспетчер Задач», вы увидите новый процесс в списке – SaveDump.exe, – вот он этим и занимается. Необхо-
20
программирование димость в подобной двухтактной схеме сброса дампа объясняется тем, что в момент возникновения критической ошибки работоспособность драйверов файловой системы уже не гарантируется, и операционная система не может позволить себе их использовать, ограничиваясь временным размещением дампа в виртуальной памяти. Кстати, если имеющегося объема виртуальной памяти окажется недостаточно (Дополнительно → Параметры быстродействия → Виртуальная память), сброс дампа окажется невозможным. Если же система от загрузки отказывается, упорно забрасывая вас голубыми экранами смерти, вспомните о существовании клавиши <F8> и выберите пункт «Загрузка последней удачной конфигурации («Last Known Good Configuration»). Более радикальной мерой является запуск системы в безопасном (safe) режиме с минимумом загружаемых служб и драйверов. Переустановка системы – это крайняя мера и без особой нужды к ней лучше не прибегать. Лучше войдите в «консоль восстановления» и перетащите файл дампа на другую машину для его исследования.
Подключение дампа памяти Для подключения дампа памяти к отладчику Windows Debugger (windbg.exe) в меню «File» выберите пункт «Crash Dump» или воспользуйтесь горячей комбинацией <Ctrl-D>. В отладчике i386kd.exe для той же цели служит ключ «–z» командной строки, за которым следует полный путь к файлу дампа, отделенный от ключа одним или несколькими пробелами, при этом переменная окружения _NT_SYMBOL_PATH должна быть определена и содержать полный путь к файлам символьных идентификаторов, в противном случае отладчик аварийно завершит свою работу. Как один из вариантов можно указать к командой строке ключ «–y», и тогда экран консоли будет выглядеть так: «i386kd –z C:\WINNT\memory.dmp -y C:\WINNT\Symbols», причем отладчик следует вызывать из Checked Build Environment/Free Build Environment консоли, находящейся в папке Windows 2000 DDK, иначе у вас ничего не получится. Хорошая идея – ассоциировать dmp-файлы с отладчиком i386kd, запуская их одним ударом «Enter» из FAR. Впрочем, выбор средства анализа – дело вкуса. Комуто нравится KAnalyze, а кому-то достаточно и простенького DumpChk. Выбор аналитических инструментов чрезвычайно велик (один лишь DDK содержит четыре из них!), и чтобы хоть как-то определиться с выбором, мы остановимся на i386kd.exe, также называемом Kernel Debugger. Как только консоль отладчика появится на экране (а Kernel Debugger – это консольное приложение, горячо любимое всеми, кто провел свою молодость за текстовыми терминалами), курсор наскоро дизассемблирует текущую машинную инструкцию и своим тревожным мерцанием затягивает нас в пучину машинного кода. «Ну что, глазки строить будем или все-таки дизассемблировать?» – незлобно ворчим мы, выбивая на клавиатуре команду «u», заставляющую отладчик продолжить дизассемблирование.
№12(13), декабрь 2003
Судя по символьным идентификаторам PspUnhandled ExceptionInSystemThread и KeBugCheckEx, мы находимся глубоко в ядре, а точнее – в окрестностях того кода, что выводит BSOD на экран: Ëèñòèíã 22. Ðåçóëüòàò äèçàññåìáëèðîâàíèÿ ïîäêëþ÷åííîãî äàìïà ïàìÿòè ñ òåêóùåãî àäðåñà 8045249c 6a01 push 0x1 kd>u _PspUnhandledExceptionInSystemThread@4: 80452484 8B442404 mov eax, dword ptr [esp+4] 80452488 8B00 mov eax, dword ptr [eax] 8045248A FF7018 push dword ptr [eax+18h] 8045248D FF7014 push dword ptr [eax+14h] 80452490 FF700C push dword ptr [eax+0Ch] 80452493 FF30 push dword ptr [eax] 80452495 6A1E push 1Eh 80452497 E8789AFDFF call _KeBugCheckEx@20 8045249C 6A01 push 1 8045249E 58 pop eax 8045249F C20400 ret 4
В стеке ничего интересного также не содержится, судите сами (просмотр содержимого стека осуществляется командной «kb»): Ëèñòèíã 23. Ñîäåðæèìîå ñòåêà íå äàåò íèêàêèõ íàìåêîâ íà ïðèðîäó èñòèííîãî âèíîâíèêà kd> kb ChildEBP RetAddr Args to Child f403f71c 8045251c f403f744 8045cc77 f403f74c ↵ ntoskrnl!PspUnhandledExceptionInSystemThread+0x18 f403fddc 80465b62 80418ada 00000001 00000000 ↵ ntoskrnl!PspSystemThreadStartup+0x5e 00000000 00000000 00000000 00000000 00000000 ↵ ntoskrnl!KiThreadStartup+0x16
Такой поворот событий ставит нас в тупик. Сколько бы мы ни дизассемблировали ядро, это ни на йоту не приблизит нас к источнику критической ошибки. Что ж, все вполне логично. Текущий адрес (8045249Сh) лежит далеко за пределами драйвера-убийцы (0BE80A00h). Хорошо, давайте развернемся и пойдем другим путем. Помните тот адрес, что высвечивал голубой экран смерти? Не помните – не беда! Если это только не запрещено настройками, копии всех голубых экранов сохраняются в Журнале системы. Откроем его («Панель управления» → »Администрирование» → »Просмотр событий»): Ëèñòèíã 24. Êîïèÿ ãîëóáîãî ýêðàíà ñìåðòè, ñîõðàíåííàÿ â ñèñòåìíîì æóðíàëå Êîìïüþòåð áûë ïåðåçàãðóæåí ïîñëå êðèòè÷åñêîé îøèáêè: 0x0000001e (0xc0000005, 0xbe80b000, 0x00000000, 0x00000000). Microsoft Windows 2000 [v15.2195] Êîïèÿ ïàìÿòè ñîõðàíåíà: C:\WINNT\MEMORY.DMP.
Отталкиваясь от категории критической ошибки (0x1E), мы без труда сможем определить адрес инструкции-убийцы – 0xBE80B000 (в приведенном выше листинге он выделен красным шрифтом). Даем команду «u BE80B000» для просмотра его содержимого и видим: Ëèñòèíã 25. Ðåçóëüòàò äèçàññåìáëèðîâàíèÿ äàìïà ïàìÿòè ïî àäðåñó, ñîîáùåííîìó ãîëóáûì ýêðàíîì ñìåðòè kd>u 0xBE80B000 be80b000 a100000000 be80b005 c20800 ret be80b008 90
mov 0x8 nop
eax,[00000000]
21
программирование be80b009 be80b00a be80b00b be80b00c be80b00d
90 90 90 90 90
nop nop nop nop nop
Ага! Вот это уже больше похоже на истину! Инструкция, на которую указывает курсор (в тексте она выделена красным цветом), обращается к ячейке с нулевым адресом, возбуждая тем самым губительное для системы исключение. Теперь мы точно знаем, какая ветка программы вызвала сбой. Хорошо, а как быть, если копии экрана смерти в нашем распоряжении нет? На самом деле, синий экран всегда с нами, надо только знать, где искать! Попробуйте открыть файл дампа в любом hex-редакторе, и вы обнаружите следующие строки: Ëèñòèíã 26. Êîïèÿ ãîëóáîãî ýêðàíà â çàãîëîâêå äàìïà ïðîãðàììû
С первого же взгляда удается опознать все основные Bug Check-параметры: 1E 00 00 00 – это код категории сбоя 0x1E (на x86 процессорах наименее значимый байт располагается по меньшему адресу, то есть все числа записываются задом наперед); 05 00 00 C0 – код исключения ACCESS VIOLATION; а 00 B0 80 BE – и
22
есть адрес машинной команды, породившей это исключение. В комбинации же 0F 00 00 00 93 08 легко узнается номер билда системы, стоит только записать его в десятичной нотации. Для просмотра Bug Check-параметров в более удобочитаемом виде можно воспользоваться следующей командой отладчика: «dd KiBugCheckData»: Ëèñòèíã 27. Bug Check ïàðàìåòðû, îòîáðàæàåìûå â óäîáî÷èòàåìîì âèäå kd> dd KiBugCheckData dd KiBugCheckData 8047e6c0 0000001e c0000005 8047e6d0 00000000 00000000 8047e6e0 00000000 00000000 8047e6f0 00000000 00000000 8047e700 00000000 00000000 8047e710 00000000 00000000 8047e720 00000000 00000000 8047e730 00000000 e0ffffff
be80b000 00000001 00000000 00000000 00000000 00000000 00000000 edffffff
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00020000
Другие полезные команды: «!drivers» – выводящая список драйверов, загруженных на момент сбоя, «!arbiter» – показывающая всех арбитров вместе с диапазонами арбитража, «!filecache» – отображающая информацию о кэше файловой системы и PT, «!vm» – отчитывающаяся об использовании виртуальной памяти и т. д. – всех не перечислишь! (полный перечень команд вы найдете в руководстве по своему любимому отладчику).
программирование Конечно, в реальной жизни определить истинного виновника краха системы намного сложнее, поскольку всякий нормальный драйвер состоит из множества сложно взаимодействующих функций, образующих запутанные иерархические комплексы, местами пересеченные туннелями глобальных переменных, превращающих драйвер в самый настоящий лабиринт. Приведем только один пример. Конструкция вида «mov eax, [ebx]», где ebx == 0, работает вполне нормально, послушно возбуждая исключение, и пытаться поговорить с ней по-мужски – бессмысленно! Нужно найти тот код, который записывает в EBX нулевое значение, и сделать это непросто. Можно, конечно, просто прокрутить экран вверх, надеясь, что на данном участке программный код выполнялся линейно, но никаких гарантий, что это действительно так, у нас нет, равно как нет и возможности обратной трассировки (back trace). Грубо говоря, адрес предшествующей машинной инструкции нам неизвестен, и закладываться на прокрутку экрана нельзя! Загрузив подопытный драйвер в любой интеллектуальный дизассемблер, автоматически восстанавливающий перекрестные ссылки (например IDA PRO), мы получим более или менее полное представление о топологии управляющих ветвей программы. Конечно, ди-
зассемблирование в силу своей статической природы, не гарантирует, что управление не перекинулось откуда-то еще, но по крайней мере сужает круг поиска. Вообще же, о дизассемблировании написано множество хороших книг (и «Фундаментальные основы хакерства» Криса Касперски в том числе), поэтому не будем останавливаться на этом вопросе, а просто пожелаем всем читателям удачи.
Ðèñóíîê 6. Îòëàä÷èê i386kd çà ðàáîòîé. Íåñìîòðÿ íà ñâîþ îòòàëêèâàþùóþ âíåøíîñòü, ýòî ÷ðåçâû÷àéíî ìîùíûé è óäîáíûé â ðàáîòå èíñòðóìåíò, ïîçâîëÿþùèé ïðîâîðà÷èâàòü óìîïîìðà÷èòåëüíûå ïàññàæè íàæàòèåì âñåãî ïàðû-òðîéêè êëàâèø (îäíà èç êîòîðûõ âûçûâàåò âàø ñîáñòâåííûé ñêðèïò)
Ðèñóíîê 7. windbg c çàãðóæåííûì äàìïîì ïàìÿòè. Îáðàòèòå âíèìàíèå: îòëàä÷èê ñàìîñòîÿòåëüíî âûñâå÷èâàåò Bug Check-êîäû, íå îæèäàÿ, ïîêà ìû îá ýòîì åãî ïîïðîñèì, à ïðè ïîïûòêå äèçàññåìáëèðîâàíèÿ èíñòðóêöèè, âîçáóäèâøåé èñêëþ÷åíèå, íà ýêðàíå âûñêàêèâàåò «Module Load: W2K_KILL.SYS», ñîîáùàþùàÿ íàì èìÿ äðàéâåðà-óáèéöû. Âðîäå áû ìåëî÷ü, à êàê ïðèÿòíî!
№12(13), декабрь 2003
23
УНИКАЛЬНЫЕ СОБЫТИЯ НА КОМПЬЮТЕРНОМ РЫНКЕ Впервые организованная в 1989 году, выставка Неделя Информационных Технологий «IT Week Russia», известная в прошлом как Comtek, за пятнадцать лет своего существования пережила и взлеты и падения. В предыдущие годы в Неделю Информационных Технологий входила выставка Сomtek, которая состояла из нескольких направлений, и конференция E-Business. Развитие выставки в течение последних лет привело к необходимости выделить отдельные разделы в самостоятельные выставки. С этого года в Неделю Информационных Технологий будут входить пять самостоятельных выставок и две конференции. Этот шаг позволил расширить масштаб выставки, объединяющей все аспекты компьютерного бизнеса, что, в свою очередь, дает возможность привлечь к участию в выставке большее число компаний, занятых во всех сферах индустрии информационных технологий. Давид Патеишвили, директор выставки, сказал: «В этом году мы расширили темы, представленные на экспозиции, которые теперь охватывают все области компьютерной индустрии. Это дает превосходную возможность и участникам, и посетителям выставки принять участие и ознакомиться сразу с пятью выставками и двумя конференциями, проходящими в одно время и в одном месте. Это также позволит нам улучшить маркетинговую и рекламную кампании для каждой из выставок и конференций, проходящих в рамках Недели Информационных Технологий, с учетом целевой аудитории, специфичной для каждой из них. Хочется добавить, что некоторые выставки, которые будут проходить в рамках Недели Информационных технологий, не имеют аналогов в России, являясь тем самым уникальными». В рамках Недели Информационных Технологий пройдут следующие выставки и конференции: 1. Personal Computing Expo – общая, неспециализированная выставка, ориентированная на конечных пользователей. В ней представлены производители и дистрибьюторы персональных компьютеров и периферии, компьютерных игр, дистрибьюторы сотовой техники и портативных компьютеров, интернет- и контентпровайдеры и многие другие. 2. Hardware & Peripherals Expo – специализированная выставка, на которой представлены: компьютеры, мониторы, периферийные устройства, комплектующие, накопители, коммуникационное оборудование и услуги, т.е. весь спектр hardware, ориентированного на ведение бизнеса. 3. Международная конференция eLearning Russia (Информационные технологии в образовании), на которой будут освещены последние достижения образовательных технологий в школах, вузах, а также рассмотрены вопросы дистанционного и бизнес-образования.
24
4. Software Expo – специализированная выставка, ориентированная на программные продукты для систем бухгалтерского и складского учета, комплексного ПО управления предприятием, систем управления документооборотом, систем распознавания документов, разработку ПО, защиту информации. В рамках этой выставки будет подготовлен цикл тематических семинаров, посвященных актуальным вопросам в области разработки экономических программ и систем управления бизнесом. 5. Специализированная выставка CAD/CAM/CAE представляет системы автоматизированного проектирования. Для большинства российских производителей необходимость использования САПР для оптимизации работы предприятия стала очевидной. Особенно ярко это проявляется в таких отраслях, как авиастроение, автомобилестроение, тяжелое машиностроение, архитектура, строительство, нефтегазовая промышленность. 6. eLearn Expo – специализированная выставка, на которой будут демонстрироваться новейшие продукты и технологии в сфере электронного обучения, предназначенные для коллективного и индивидуального пользования. Дистанционное обучение через сети Internet и Intranet, получившее широкое распространение в развитых странах, становится все более актуальным и для России. 7. eBusiness Russia (Электронный бизнес в России) – международная конференция, посвященная вопросам автоматизации бизнес-процессов, развития электронной коммерции, подбора ИТ-персонала. Выставка IT-week остается ведущей международной выставкой информационных технологий в России и странах СНГ. Это уникальное место для проведения переговоров с первыми лицами сразу нескольких крупных фирмпоставщиков оборудования и решений. Практически все крупные западные вендоры присутствуют на выставке непосредственно или при посредстве своих российских партнеров. В соответствии с растущими потребностями рынка и увеличением числа участников экспозиция расширила площадь, которая в этом году составит 8000 кв. м. В выставках, которые пройдут в течение 4 дней, примут участие 250 ведущих компаний отрасли из 25 стран мира. Ожидается, что число посетителей выставки превысит 75 000 человек, включая руководителей верхнего и среднего звена, технических специалистов и IT-администраторов, из более 500 городов России и СНГ. «IT Week 2004», 15-ая Международная Выставка Информационных Технологий пройдет в «Экспоцентре» на Красной Пресне в Москве с 26 по 29 апреля 2004 года.
администрирование
РЕШЕНИЕ ЗАДАЧ ИНВЕНТАРИЗАЦИИ В СЕТИ
ИВАН КОРОБКО 26
администрирование Опытный системный администратор сети, построенной на основе Microsoft Windows 2000 и Windows XP, использует сценарии загрузки для решения различных задач. Одной из таких задач является инвентаризация аппаратного обеспечения рабочих станций. Решение данной задачи актуально в компаниях с большим количеством рабочих станций. Решение задачи инвентаризации состоит из двух частей: первая часть – сбор информации с помощью сценария загрузки, написанном на VBScript и сохранение полученных данных в файл отчета на сервер в формате XML. Вторая часть – анализ полученных данных. В качестве инструмента для анализа данных предлагается создать сайт на ASP, который позволит объединить в единое целое данные о конфигурации всех рабочих станций, осуществить поиск по заданному критерию; создать файл отчета о проделанном поиске. Обе части реализованы с помощью стандартных средств Microsoft Windows, что делает их надежными в работе, легко внедряемыми.
Òàáëèöà 1
На третьем этапе, после окончания обработки запроса, поставщик пересылает результаты исходному сценарию или приложению.
Способы доступа к объектам WMI
WMI. Основные понятия Решение задачи накопления и сохранения информации об аппаратной конфигурации рабочей станции обеспечивается стандартными средствами Microsoft Windows. Одним из таких средств является Microsoft Windows Management Instrument (WMI). WMI, разработанный в 1998 году, предоставляет разработчикам программного обеспечения и администраторам сети стандартизированные способы наблюдения и управления как локальными, так и удаленными ресурсами сети.
Теоретические сведения о внутреннем устройстве WMI Исполняемым файлом, обеспечивающим функционирование WMI, является файл winmgmt.exe, находящийся в Microsoft Windows 200x каталоге c:\WINNT\system32\wbem\. Механизм работы WMI следующий: На первом этапе происходит подключение к службе WMI локального или удаленного компьютера: при обращении приложения к WMI запросы приложения пересылаются диспетчеру объектов CIM (Common Information Model (CIM) Object Manager). CIMOM обеспечивает первоначальное создание объектов и однообразный способ доступа к управляемым объектам. Наиболее простым способом подключения к удаленному компьютеру является вызов функции языка VBScript GetObject(). Подключение к удаленному компьютеру происходит с помощью протокола winmgmts. На втором этапе происходит проверка хранилища объектов. Затем запрос передается поставщику объекта. Поставщик (provider) – это интерфейс между управляемым устройством и диспетчером CIMOM. Поставщик собирает информацию об устройствах и делает их доступными для диспетчера. В состав WMI входит несколько поставщиков:
№12(13), декабрь 2003
На практике для получения доступа к объектам WMI пользуются одним из следующих шаблонов: Øàáëîí 1. Ïîëó÷åíèå äîñòóïà ê WMI-îáúåêòàì Âàðèàíò1 strComputer=”” strNameSpace=”” strClass=”” Set objElements = GetObject( "winmgmts:{ImpersonationLevel= ↵ Impersonate}!//" & strComputer & ”/ ” ↵ & strNameSpace & ”: ” & strClass) For each Element in objElements Temp=Element.Value Next Âàðèàíò2 strComputer=”” strNameSpace=”” strClass=”” Set objWMIService = GetObject( "winmgmts:{ImpersonationLevel= ↵ Impersonate}!//" & strComputer & ”/ ” ↵ & strNameSpace) Set colItems = objWMIService.InstancesOf(strClass ) For Each objItem in colItems Temp=Element.Value Next Âàðèàíò3 strComputer=”” strNameSpace=”” strClass=”” Set objWMIService = GetObject("winmgmts:{ImpersonationLevel= ↵ Impersonate }!// " & strComputer & ”/ ” ↵ & strNameSpace) Set colItems = objWMIService.ExecQuery(“SELECT ïîëå_1, ↵ ïîëå_2, …, ïîëå_n FROM” & strClass ) For Each objItem in colItems Temp=Element.Value Next
В приведенных примерах переменная strComputer содержит имя удаленного компьютера. Если компьютер локальный, то вместо имени указывается символ «.»: strComputer=”.”; Переменная strNameSpace содержит пространство имен (см. таблицу 1). strClass – переменная, содержащая название класса. Например, для Win32 Provider, одним из классов является Win32_BIOS, соответственно, переменная strNameSpace принимает значение Root\Cimv2.
27
администрирование Инстркуция {ImpersonationLevel=Impersonate}! заставляет выполнить сценарий с привилегиями пользователя, вызывающего сценарий, а не с привилегиями пользователя, который в настоящий момент работает на рабочей станции. Таким образом, осуществляется подстановка, которая полезна при выполнении сценариев удаленного доступа на таких ОС, как Microsoft Windows 200x. Инструкция {ImpersonationLevel=Impersonate}! в Microsoft Windows 200x является выражением подстановки по умолчанию, поэтому для семейства Windows 200x ее можно опустить. Варианты 1 и 2 шаблона 1 родственны и отличаются лишь формой записи. В варианте 3 обращение к классу строится с помощью SQL-запроса, что позволяет экономить трафик. В общем случае запрос SQL выглядит следующим образом: SELECT ïîëå_1, ïîëå_2, …, ïîëå_n FROM strClass
В поле SELECT указываются поля, по которым идет выборка. Поля перечисляются через запятую, «пробелы» после запятой обязательны. Если выборка должна идти по всем полям, то вместо названий полей указывается символ «*». В поле FROM указывается один из ранее перечисленных поставщиков:
Ðèñóíîê 1. Îáúåêòíàÿ ìîäåëü WMI
28
SELECT *
FROM strClass
В зависимости от способа доступа к хранилищу размер пересылаемых данных разный (см. таблицу 2). Òàáëèöà 2
Вывод: видно, что выгодно пользоваться шаблоном 3. Несмотря на то, что код получится несколько громоздким, уменьшится межсетевой трафик, сократится время работы сценария.
Практика использования WMI Данная статья посвящена решению задачи инвентаризации. Как видно из таблицы 1, для решения этой задачи необходимо использовать Win32 Provider, которому соответствует пространство имен Root\Cimv2. Win32 Provider соответствует массив, состоящий из двух частей: идентификатора и названия ресурса, которые разделены знаком подчеркивания. Идентификатором всегда является «WIN32». С объектной моделью WMI можно ознакомиться с помощью утилиты WMI Object Browser (см. рис. 1), входящей в пакет WMI Tools. Набор утилит WMI Tools можно найти на сайте компании Microsoft: http://msdn.microsoft.com/developer/sdk/wmisdk/default.asp.
администрирование Таким образом, вариант 3 шаблона 1 примет следующий вид: Øàáëîí 1. Îáîáùåííûé âàðèàíò 3 strComputer=”” strNameSpace=” Root\Cimv2” strClass=”Win32_Value” Set objWMIService = GetObject( " winmgmts: // " & ↵ strComputer & ”/ ” & strNameSpace) Set colItems = objWMIService.ExecQuery(“SELECT ïîëå_1, ↵ ïîëå_2, …, ïîëå_n FROM” & strClass ) For Each objItem in colItems Temp=Element.Value Next
Приведем пример получения информации о материнской плате на основе обобщенного варианта 3 рабочей станции ComputerName (VBScript). Массив данных, в котором содержится информация о материнской плате, называется WIN32_BIOS: Ïðèìåð 1. Ïîëó÷åíèå èíôîðìàöèè î ìàòåðèíñêîé ïëàòå ðàáî÷åé ñòàíöèè strComputer="." strNameSpace="Root\Cimv2" strClass="Win32_BIOS" Set objWMIService = GetObject("winmgmts://"&strComputer&"/ ↵ "& strNameSpace) Set colItems = objWMIService.ExecQuery("SELECT ↵ SMBIOSBIOSVersion FROM " & strClass ) For Each objItem in colItems MsgBox objItem.SMBIOSBIOSVersion Next
Необходимо отметить, что переменная objItem.SMBIOSBIOSVersion строковая (см. рис. 1). Если переменная является числом, то ее необходимо преобразовать в строковую переменную с помощью функции Сstr(). Если переменная представляет собой массив, то необходимо прочитать элементы массива и преобразовать их в строки, если элементы массива не являются строковыми переменными. Результатом выполнения данной программы будет сообщение вида:
Ðèñóíîê 2. Èíôîðìàöèÿ î ìîäåëè ìàòåðèíñêîé ïëàòû
Порядок работы сценария загрузки Сценарий загрузки, написанный на VBScript, работает в соответствии со следующим алгоритмом. На первой стадии работы, для идентификации рабочей станции системным администратором, сценарием загрузки определяются следующие параметры: имя рабочей станции; домен, к которому принадлежит рабочая станция; версия операционной системы, установленной на рабочей станции, учетная запись пользователя; текущая дата. На втором этапе определяются аппаратные характеристики рабочей станции с помощью WMI. На третьем этапе формируется файл отчета в формате XML. Данные, хранящиеся в XML, могут быть экспортированы для последующей обработки в одно из следующих приложений: Microsoft Excel, Microsoft Access, Microsoft SQL
№12(13), декабрь 2003
или обработаны любым другим приложением, предназначенным для этой цели. Об одном из таких альтернативных приложений и пойдет речь во второй части. Стоит лишь добавить, что оно также будет создано с помощью стандартных средств, предоставляемых компанией Microsoft – ASP и HTML. Запись файла отчета на диск сервера является заключительным этапом, однако формирование файла отчета идет на протяжении всего времени выполнения сценария загрузки. Поэтому начать описание работы сценария загрузки необходимо с процесса формирования файла отчета.
Формирование файла отчета Файл отчета представляет собой текстовый файл в кодировке Unicode с данными, записанными в формате XML. Extensible Markup Language (XML) – это язык разметки документов, созданный Microsoft, структурированного хранения информации. Полную спецификацию XML см. на сайте: http://www.w3c.org/xml Файл отчета формируется в течение всего времени выполнения сценария загрузки методом накопления. Определяя требуемые для отчета параметры по ходу выполнения сценария загрузки, происходит пополнение переменной. Для этого используют выражение вида: temp=temp+data, где выражение data строится по шаблону <раздел> значение </раздел>. Названия разделов чувствительны к регистру. В подтверждение приведем пример, в котором в раздел «Date» XML-файла помещают текущую дату и точное время запуска сценария загрузки: temp = temp + ”<Date>” + Date() + ”; ” + Time() + ”</Date>”
В конце сценария загрузки открывается текстовый файл, в него записывается содержимое переменной temp: Ïðèìåð 2. Ôîðìèðîâàíèå ôàéëà îò÷åòà Set fso = CreateObject("Scripting.FileSystemObject") Set f = fso.OpenTextFile(FileName, 2, True) f.Write "temp" f.Close
Переменная FileName, фигурирующая в данном примере, состоит из двух частей – пути к папке на сервере, в которой будут храниться файлы отчетов со всех рабочих станций; имени файла. Имя файла должно совпадать с именем рабочей станции. В папку, предназначенную для хранения файлов отчетов, пользователи группы Everyone должны иметь возможность записи. Второе требование к этой папке – ее скрытость от всех пользователей. Исходя из ранее сказанного, отметим, что переменная FileName имеет следующий вид: \\server\folder$\PC_name.xml.
Определение параметров рабочей станции Определяя те или иные параметры рабочей станции, многократно повторяется один и тот же программный код, претерпевающий небольшие изменения. Для сокращения программного кода рекомендуется названия WMI-классов, к которым происходит обращение, объединить в массив. Шаблон будет выглядеть следующим образом:
29
администрирование Øàáëîí 2. Îáåñïå÷åíèå óíèâåðñàëüíîãî äîñòóïà ê íåñêîëüêèì êëàññàì WMI dim strClass strClass=Array(”Win32_Value1”, ”Win32_Value2”,… ↵ ”Win32_Value?”) Set objWMIService = GetObject( " winmgmts: //./ ↵ Root\Cimv2 ") for a=0 to ? Set colItems = objWMIService.ExecQuery(“SELECT * ↵ FROM” & strClass(a) ) For Each objItem in colItems Select case a Case 0 b=b+1 temp=temp+"<Parametr1" + cstr(b) +">" temp=temp+"<Parametr2" + cstr(objItem.Value1) +">" temp=temp+"<Parametr3" + cstr(objItem.Value2) +">" …………………………………………………… temp=temp+"<Parametrµ" + cstr(objItem.Valueµ) +">" temp=temp+"</Parametr1" + cstr(b) +">" Case1 c=c+1 temp=temp+"<Parametr1" + cstr(c) +">" temp=temp+"<Parametr2" + cstr(objItem.Value1) +">" temp=temp+"<Parametr3" + cstr(objItem.Value2) +">" …………………………………………………… temp=temp+"<Parametr?" + cstr(objItem.Value?) +">" temp=temp+"</Parametr1" + cstr(c) +">" ……………………………………………………………………… Case ? y=y+1 temp=temp+"<Parametr1" + cstr(y) +">" temp=temp+"<Parametr2" + cstr(objItem.Value1) +">" temp=temp+"<Parametr3" + cstr(objItem.Value2) +">" …………………………………………………… temp=temp+"<Parametr?" + cstr(objItem.Value?) +">" temp=temp+"</Parametr1" + cstr(y) +">"
Set colItems = objWMIService.InstancesOf(strClass(a)) For Each objItem in colItems select case a case 0 FileName="\\server\folder\" & cstr(objItem.Name) & ".xml" temp=temp + "<Computer><PCName>" + objItem.Name + ↵ "</PCName>" + chr(10) temp=temp + " <Domain> " + objItem.Domain + ↵ " </Domain>" + chr(10) temp=temp + "<User> " + objItem.Username + ↵ " </User>" + chr(10) temp = temp + "<Date>" + cstr(Date()) + "; ↵ " + cstr(Time()) + "</Date> </Computer>" + chr(10) case 1 temp=temp + "<MB> <Version> " + objItem.Version + ↵ " </Version>" + chr(10) temp=temp + "<Mbinfo> " + objItem.SMBIOSBIOSVersion + ↵ " </Mbinfo></MB>" + chr(10) case 2 b=b+1 temp=temp + "<CD-ROM" + cstr(b) +"> <Model>" + ↵ objItem.Caption + " </Model>" + chr(10) temp=temp + "<Description>" + objItem.Description + ↵ " </Description>" + chr(10) temp=temp + "<Letter>" + objItem.Drive + ↵ " </Letter> </CD-ROM" + cstr(b) +">" + chr(10) end select Next Next Set fso = CreateObject("Scripting.FileSystemObject") Set f = fso.OpenTextFile(FileName, 2, True) f.Write "<inf>" & temp & "</inf>" f.Close
Результатом данного сценария является файл в формате XML. Формат файла совпадает с названием рабочей станции (см. рис. 3).
End Select Next Next Set FileName=”\\server\folder” Set fso = CreateObject("Scripting.FileSystemObject") Set f = fso.OpenTextFile(FileName, 2, True) f.Write temp f.Close
Поскольку поля в разных классах разные, то использование варианта 3 шаблона 1 становится невозможным – необходимо использовать вариант 1 или 2. В шаблоне 2 строка: Set colItems = objWMIService.ExecQuery(“SELECT * & strClass(a))
FROM” ↵
заменяется на строку: Set colItems = objWMIService.InstancesOf(strClass(a))
Приведем конкретный пример, в котором определим некоторые данные о рабочей станции. Названия параметров и соответствующие им названия WMI-классов приведены таблице: Òàáëèöà 3 Ðèñóíîê 3. Ïðèìåð XML-ôàéëà
Полная версия сценария загрузки приведена в Приложении 1.
Обработка полученных данных Ïðèìåð 3 Ñîçäàíèå XML-ôàéëà dim strClass strClass=Array("Win32_ComputerSystem", "Win32_BIOS", ↵ "Win32_CDROMDrive") Set objWMIService = GetObject("winmgmts://./Root\Cimv2") for a=0 to 2
30
Инструмент, позволяющий обработать данные о рабочих станциях, собранные в XML-файлы, представляет собой сайт, построенный на основе ASP. Выбор ASP обусловлен его способностью работать с OLE-объектами. Инструмент представляет сайт, точкой входа в который является стра-
администрирование ница на языке HTML. Сайт создан на основе окон (Frameset): файл default.htm делит окно браузера на два столбца. Текст файла default.htm (HTML) см. в Приложении 2. Остальные страницы написаны на ASP и взаимосвязаны друг с другом. Для их создания выбран VBScript. VBScript выбран потому, что является языком, поставляемым с Microsoft Windows; обладает необходимыми возможностями для реализации данного проекта, имеет простой синтаксис. С помощью файла xml_list.asp осуществляется чтение XML-файлов в заданном каталоге, составляется список рабочих станций или пользователей в домене. Выбор списка осуществляется в HTML-файле. Вторая задача, решаемая этим файлом, – осуществление поиска по указанному значению. Поиск является сквозным, т.е. поиск происходит по всем полям всех файлов. Результатом поиска является таблица, левый столбец которой содержит в себе название рабочей станции, правый – значение параметра в контексте (см. рис. 5). Второй ASP-файл – analyse.asp, предназначен для отображения информации по интересующей системного администратора рабочей станции.
Принцип работы файла xml_list.asp Чтение данных из XML-файла Процесс чтения значений параметров XML-файла, как и других структурированных файлов, состоит из нескольких этапов: получение списка файлов, которые необходимо обработать; чтение полей и занесение их в массивы; упорядочивание массивов по одному из полей; отображение полученной информации. Рассмотрим каждый из этих этапов подробнее.
Шаг 1. Получение списка файлов в указанном каталоге Получение списка файлов осуществляется с помощью Windows Hosting Script (WSH). WSH был предложен в 1998 году Microsoft в качестве инструмента разработки и выполнения сценариев для операционной системы Microsoft Windows. Бесспорным достоинством WSH является тот факт, что он входит в комплект поставки Microsoft Windows и поддерживает два встроенных в Microsoft Windows языка программирования – Microsoft Visual Basic Script Edition (VBScript) и Miscrosoft Java Script Edition(Jscript). В приведенном ниже примере (VBScript), осуществляется чтение имен всех файлов, находящихся в каталоге, указанном в переменной Path, и вывод этой информации на экран: Ïðèìåð 4. ×òåíèå íàçâàíèé ôàéëîâ, ñîäåðæàùèõñÿ â êàòàëîãå Path="\\Server\Folder" Set a=Wscript.CreateObject("Wscript.Shell") Set fso=CreateObject("Scripting.FileSystemObject") Set oFolder=fso.GetFolder(a.ExpandEnvironmentStrings(Path))
№12(13), декабрь 2003
Set oFiles=oFolder.Files For each oFile in oFiles temp=temp+oFile.Name & chr(10) next MsgBox temp
Шаг 2. Чтение полей и занесение их в массивы Чтение полей XML-файла осуществляется с помощью объекта Microsoft.XMLDOM. XML-файл представляет собой структурированную базу данных. Для чтения полей XML-файла необходимо четко представлять принцип построения карты XML-файла. Рассмотрим карту, представленную на рисунке 3: она имеет 4 раздела – Computer, MB, CD-ROM1 и CD-ROM2. Видно, что в ширину XML-файл имеет четыре ячейки. Количество ячеек можно определить с помощью функции .childNodes.Lenght-1. Каждая из ячеек имеет глубину – второе измерение (см. рис. 3). Глубина одной ячейки может быть отлична от другой. В приведенном примере глубина каждой из ячеек различна. Например, глубина ячейки Computer равна четырем – PCName, Domain, User, Data. Глубина ячейки определяется функцией функции .childNodes(i). childNodes.Lenght-1, где i – номер ячейки. Название ячейки осуществляется с помощью функции .childNodes(i).childNodes(j).NodeName, где i – номер ячейки, j – ее глубина. Вызывая функция .childNodes(2).childNodes(0).NodeName для рис. 3, в результате получим «Model». Необходимо отметить, что нумерация и ширины поля XML и глубина ячеек начинаются с нуля. Чтение значения параметра осуществляется с помощью функции .childNodes(i).childNodes(j).Text, где i и j имеют ту же смысловую нагрузку, что и ранее. Необходимо отметить одну особенность: при чтении значения уровня, ниже которого есть уровень, который также содержит значения, происходит логическое сложение данных нижнего уровня и присовокупление их к верхнему. Рассмотрим этот процесс на примере карты на рис. 3. Результатом чтения .childNodes(3).Text будет выражение «SONY DVD-ROM DDU1211 CD-ROM Drive F:». Именно эта способность сквозного просмотра ячейки до дна будет использована при поиске по заданному значению. Приведем пример, который иллюстрирует эту особенность: Ïðèìåð 5. Ñêâîçíîå ÷òåíèå ÿ÷åéêè XML-ôàéëà <%@ Language=VBScript%> <% path="xml\10000PC.xml" set xmlVisitor=server.CreateObject("Microsoft.XMLDOM") XMLFile=xmlVisitor.load(server.MapPath(path)) With xmlVisitor.documentElement response.write .childNodes(3).text End With set xmlVisitor=Nothing %>
Зная основные принципы чтения XML-файла, приведем пример, в котором сначала происходит чтение списка из названий файлов, находящихся в каталоге; затем чтение двух полей в каждом файле – название рабочей станции и имени пользователя с последующим занесением в массив каждого из параметров. Необходимо отметить, что в приведенном примере переопределяется размер массивов, в которые в конце примера будут заноситься названия рабочих станций и имен пользователей. Переопределение размеров массивов осуществляется с помощью функции redim preserve array_name(count), где array_name – название мас-
31
администрирование сива, а count – новый размер массива. Полный листинг файла xml_list.asp см. в Приложении 2. Ïðèìåð 6. Ôîðìèðîâàíèå ìàññèâîâ èç íàçâàíèé ðàáî÷èõ ñòàíöèé è ó÷åòíûõ çàïèñåé ïîëüçîâàòåëåé <%@ Language=VBScript%> <% path="\\server\folder" Set a=CreateObject("Wscript.Shell") Set fso=CreateObject("Scripting.FileSystemObject") Set oFolder=fso.GetFolder(a.ExpandEnvironmentStrings(path)) Set oFiles=oFolder.Files set xmlVisitor=server.CreateObject("Microsoft.XMLDOM") dim array_pcname() dim array_username() redim preserve array_pcname(oFiles.count) redim preserve array_username(oFiles.count) i=0 For each oFile in oFiles XMLFile=xmlVisitor.load(server.MapPath(path ↵ & oFile.Name)) With xmlVisitor.documentElement UN=.childNodes(0).childNodes(2).text array_filename(i)=oFile.Name array_pcname(i)=.childNodes(0). ↵ childNodes(0).text array_username(i)=right(UN, ↵ len(UN)-instr(UN,"\")) i=i+1 End With Next set xmlVisitor=Nothing %>
Шаг 3. Упорядочивание массивов по одному из полей Упорядочивание массива является классической задачей, поэтому нет необходимости углубляться в то, как это делается. В данном случае применен пузырьковый метод упорядочивания массивов. Следует отметить, что, читая XML-файлы, формируются два массива. Задача состоит в том, чтобы упорядочить один из массивов, при этом не нарушить соответствия элементов второго массива первому массив. Для достижения этой цели используется третий массив – array_sort(i), элементам которого присваиваются в зависимости от поставленного условия элементы первого или второго массивов. Ïðèìåð 7. Óïîðÿäî÷èâàíèå âçàèìîñâÿçàííûõ ìàññèâîâ <%@ Language=VBScript%> <% path="\\server\folder" ………………………………… 'Âåðõíÿÿ ãðàíèöà ìàññèâîâ îïðåäåëÿåòñÿ ñ ïîìîùüþ ôóíêöèè 'Ubound(). Óñëîâèå ñîðòèðîâêè ìàññèâà îñóùåñòâëÿåòñÿ ñ 'ïîìîùüþ StrComp(). dim array_sort () redim preserve array_sort(oFiles.count) size_array=ubound(array_sort) ………………………………… on error resume next for j=0 to size_array for i=0 to size_array if strcomp(array_sort(i),array_sort(i+1),0)=1 then temp=array_sort(i) array_sort(i)=array_sort(i+1) array_sort(i+1)=temp temp=array_pcname(i) array_pcname(i)=array_pcname(i+1) array_pcname(i+1)=temp temp=array_pcname(i) array_pcname(i)=array_pcname(i+1) array_pcname(i+1)=temp end if next next %>
32
Шаг 4. Отображение полученной информации После упорядочивания массивов обработанная информация готова к отображению в браузере. В зависимости от значения параметра sort в HTML-файле, выводится либо список пользователей, либо список рабочих станций домена. Оба списка упорядочены по алфавиту. Рассмотрим механизм передачи данных из одной страницы в другую. Данные могут передаваться двумя способами: прямым и косвенным. Прямой метод: В исходной странице создается форма, которая содержит поля для ввода информации и кнопку для отправки информации и загрузки страницы, принимающей данные (HTML): Ïðèìåð 8. Ïðÿìîé ìåòîä ôîðìèðîâàíèÿ çàïðîñîâ <FORM ACTION="printer_adsi.asp" TARGET="main" METHOD="get"> <INPUT TYPE="submit" VALUE="Ïîèñê"></INPUT> <INPUT NAME="Search_Text"></INPUT> </FORM>
В разделе FORM присутствуют следующие параметры: ACTION, TARGET, METHOD. В параметре ACTION указывается файл, в который будут передаваться данные после нажатия на кнопку. Подразделом, который обязательно присутствует в разделе FORM, является INPUT. INPUT имеет следующие параметры: TYPE, NAME, VALUE. Параметр TYPE определяет вид приемника информации: кнопка (TYPE=«submit» или «reset»); окно для ввода текста (TYPE=«text»), значение по умолчанию; кнопка выбора одного параметра из группы (TYPE=«radio»). VALUE – название поля, отображаемое в объекте. NAME – имя, которое участвует в формировании запроса. Запрос, который формируется с помощью метода GET, в общем виде выглядит следующим образом: http://èìÿ_ñòðàíèöà.asp(htm)?Ï1=Ç1&Ï2=Ç2&...Ïn=Çn
В приведенной строке присутствуют следующие обозначения: П – параметр, З – значение. В используемом примере данная строка будет выглядеть следующим образом: http://printer_adsi.asp?Search_Text=value1
если в строке было введено «value1». Рассмотрим «страницу-приемник»: для получения переданных принимающей странице данных, необходимо прочитать запрос и присвоить переданные значения переменным. Данная операция, опираясь на приведенный пример, осуществляется следующим образом: Set search_value= Request.QueryString(«Search_Text»)
таким образом, параметр search_value=«value1». Косвенный метод: Косвенный метод используется для передачи данных из одной ASP-страницы в другую. Он основан на том, что
администрирование при нажатии пользователем на картинку или текст, являющийся ссылкой, сразу формируется запрос, который передает данные. Поскольку очередью принтера невозможно управлять, если рассматривать принтер как сетевое устройство, то использование протокола LDAP становится невозможным. Для доступа к очереди принтера, как ранее отмечалось, используется протокол WINNT. Для использования протокола необходимо передавать 2 параметра: сетевое имя принтера (Share Name) и название окна (Frame), в котором необходимо вывести данную страницу. Опираясь на приведенные ранее примеры, данные будут передаваться на страницу View_Printer.asp, запрос будет иметь следующий вид (ASP): Ïðèìåð 9. Êîñâåííûé ìåòîä ôîðìèðîâàíèÿ çàïðîñîâ <% <A HREF=""View_Printer.asp?Printer_to=" & printer_name ↵ & "" "target=""var"" > <IMG SRC =images\pr1.jpg ↵ BORDER=0> </A> %>
В данном проекте прямой метод используется для осуществления поиска в файлах, косвенный – для определения вида вывода информации (по названиям рабочих станций или именам пользователей). В приведенном примере определяется значение параметра sort. Если параметр sort=1, то перед сортировкой массива происходит присвоение элементов массива array_pcname(i) массиву array_sort(i). В том случае, если sort=2, происходит присвоение элементов массива array_username(i). Вывод информации осуществляется с помощью конструкции Response.Write «Value». Информация является гиперссылкой на второй фрейм. Название фрейма, в котором будет загружаться HTML-страница, указывается в параметре target. Название фрейма задается в HTMLстранице, которая является родительским объектом для обоих ASP-страниц (см. Приложение 2, файл default.htm). В гиперссылке также формируется запрос, содержащий параметр, значением которого является UNC-путь, включающий имя XML-файла, который необходимо прочитать.
target=""analyse"" title=""Ðàáî÷àÿ ñòàíöèÿ - " & ↵ array_pcname(i) &""" a>" & array_username(i) &"</a><BR>" end select next …………………………………%>
Поиск данных в XML-файле Вторая задача, решаемая файлом xml_list.asp – осуществление поиска по указанному значению. Поиск происходит по всем полям всех файлов. Результатом поиска является таблица, левый столбец которой содержит в себе название рабочей станции, правый – значение параметра в контексте. Рекурсивная передача данных в файле xml_list.asp осуществляется с помощью прямого метода, который был рассмотрен в предыдущем разделе (см. пример 8). Методика поиска основана на использовании особенности XML-файла – сквозного просмотра ячейки до дна. Более подробную информацию и наглядный пример использования этой особенности можно найти в предыдущем разделе (см. пример 5). Приведем пример, демонстрирующий реализацию процесса поиска. Параметр search_var содержит в себе искомое словосочетание: Ïðèìåð 11. Ïðîöåäóðà ïîèñêà â XML-ôàéëàõ <%@ Language=VBScript%> <%………………………………… XMLFile=xmlVisitor.load(server.MapPath(fname ↵ & oFile.Name)) For each oFile in oFiles With xmlVisitor.documentElement For i=0 to .childNodes.length-1 if instr(Lcase(.childNodes(i).text),LCase(search_var)) then Response.Write " <TR> <TD width=100><H6><a ↵ href=analyse.asp?FN=" & fname & ofile.name & " ↵ target=""analyse"">" & ↵ left(oFile.Name,len(oFile.Name)-4)& " </a> </TD><H6> ↵ <TD><H6>" & .childNodes(i).text & "</TD><H6></TR>" end if Next End With Next Response.Write "</Table>" …………………………………%>
Ïðèìåð 10. Ôîðìèðîâàíèå çàïðîñîâ â çàâèñèìîñòè îò çíà÷åíèÿ ïàðàìåòðà sort <%@ Language=VBScript%> <% path="\\server\folder" ………………………………… set sort_var = Request.QueryString("sort") select case sort_var case 1 for i=0 to size_array array_sort(i) = array_pcname(i) next case 2 for i=0 to size_array array_sort(i) = array_username(i) next end select ………………………………… for i=0 to size_array-1 select case sort_var case 1 response.write "<a href=analyse.asp?FN=" & fname & ↵ array_filename(i+1) & "&Sort=" & sort_var & " ↵ target=""analyse"" title=""Èìÿ ïîëüçîâàòåëÿ - " & ↵ array_username(i) &""" a>" & array_pcname(i) &"</a><BR>" case 2 response.write "<a href=analyse.asp?FN=" & fname & ↵ array_filename(i+1) & "&Sort=" & sort_var & " ↵
№12(13), декабрь 2003
Ðèñóíîê 4. Ðåçóëüòàò ïîèñêà
33
администрирование Принцип работы файла analyse.asp
чтение переданного параметра из файла xml_list.asp,
Стилизация оформления страниц
чтение параметров из XML-файла и формирование от-
содержащего UNC-путь и название XML-файла;
Обе ASP-страницы используют таблицу стилей и работают в кодировке WIN-1251. Стили описываются в подключаемом файле style.css (см. Приложение 2) .Файл стилей указывается в разделе LINK, необходимая кодировка – в разделе META (HTML):
чета; вывод результата на экран. Чтение параметра осуществляется с помощью функции Request.QueryString(), которая была ранее многократно описана. Затем указанный в запросе XML-файл открывается для чтения. Чтение файла осуществляется по описанной ранее методике.
Ïðèìåð 12. Óñòàíîâêà êîäèðîâêè è ÷òåíèå òàáëèöû ñòèëåé <HEAD> <LINK HREF="style.css" TYPE=text/css REL=stylesheet> <META HTTP-EQUIV ="Content-Type" CONTENT="text/html; CHARSET=windows-1251"> </HEAD>
Параметр CHARSET отвечает за выбор кодировки, в которой будет отображаться документ. После задания таблицы стилей и подключения этой таблицы в ASP или HTML-файле, можно приступить к использованию данной таблицы. Опираясь на приведенный пример таблицы стилей, в ASP- или HTML-файле открывается и закрывается соответствующий раздел – тэг, например: <H4> «Hellow» </H4>. В приведенном примере начертание слова Hellow будет выдержано в стиле <H4>, т.е. будет написано шрифтом Arial 11-го размера.
Формирование страницы отчета Процесс формирования страницы отчета состоит из двух этапов:
Ðèñóíîê 5. Ñòàòèñòèêà ïî ðàáî÷åé ñòàíöèè
34
Внедрение продукта Готовый продукт, как отмечалось в самом начале статьи, состоит из двух частей – сценария загрузки, который обеспечивает сбор информации, и сайта на ASP, с помощью которого осуществляется анализ собранной информации о рабочих станциях домена.
Внедрение сценария загрузки Внедрение сценария загрузки состоит из нескольких этапов: В свойствах каждого пользователя необходимо прописать в разделе Logon Script сценарий загрузки (см. рис. 6). Поскольку сценарий должен быть гибким, то рекомендуется создать файл Script.bat и в нем прописывать скрипты. Предлагаемое модульное решение в случае сбоя позволит быстро справиться с возникшей проблемой, при этом лишив пользователя минимального количества сервисов, которые предлагаются набором сценариев загрузки.
администрирование
Ðèñóíîê 7. Ãðóïïîâûå ïîëèòèêè
Установка сайта и особенности конфигурирования IIS
Ðèñóíîê 6. Ñöåíàðèé çàãðóçêè
Естественно, что прописывать сценарий загрузки для каждого пользователя вручную – занятие неблагодарное, поэтому предлагается скрипт, который позволит автоматизировать данную задачу. Скрипт будет прописан всем пользователям домена, кроме тех, которые входят в группу. Название файла присваивается Logon Script (см. рис. 6). Приведенный скрипт перебирает учетные записи всех пользователей домена и проверяет членство пользователя в группе. Если пользователь не входит в группу, то в свойствах этого пользователя прописывается сценарий загрузки. Необходимо отметить, что сценарий загрузки самостоятельно определяет название домена, в котором находится пользователь, запускающий скрипт; скрипт должен быть запущен с правами администратора, т.к. изменения в Active Directory могут быть внесены только системным администратором; для увеличения скорости отработки скрипта рекомендуется запускать сценарий на контроллере домена; группа, созданная для пользователей, которым сценарий загрузки не нужен, может быть создана в любом месте Active Directory; группа должна быть глобальной; название группы и скрипта, который прописывается в свойствах пользователя, могут быть изменены в ходе выполнения скрипта. Текст скрипта см. в Приложении 1 – файл auto_script.vsb. Файл Script.bat (пример файла см. в Приложении 1) и VBS-файл должны находиться в каталоге Netlogon контроллера домена. Физически эта папка находится в каталоге с установленной операционной системой в подкаталоге SYSVOL\Domain\Script\. При загрузке рабочей станции выполняется сценарий загрузки. На время выполнения сценария загрузки необходимо скрыть CMD-панель, в которой выполняется скрипт, и приостановить загрузку рабочего стола до окончания работы всего скрипта. Необходимы результат достигается использованием групповых политик. В разделе групповой политики «User Configuration» вам необходимо, соответственно, включить «Run legacy logon script synhronously» (Запускать сценарий загрузки синхронно) и «Run legasy script hidden» (Запускать сценарий скрыто).
№12(13), декабрь 2003
Для работы ASP-страницы, созданный сайт необходимо опубликовать с помощью IIS на любом компьютере домена. Желательно, чтобы этим компьютером был компьютер, который функционирует круглосуточно. Таким компьютером является сервер. Теоретически просматривать результаты могут все пользователи сети, однако это нерационально. Необходимо назначить следующие права доступа на папку, в которой опубликован сайт: группе «Domain Admins» необходимо предоставить уровень доступа «Full Control» на папку с сайтом; остальные группы и пользователи должны быть удалены (см. рис. 8). В настройке IIS для данного сайта в его свойствах необходимо, как показано на рис. 9, войти во вкладку «Authentication Methods», нажав на кнопку «Edit». Затем выключить анонимный доступ (Anonnymos access), убрав галку напротив соответствующей записи. В разделе «Authenticated access» необходимо установить галку только напротив «Basic authentication». Желательно включить «Integrated Windows authentication» для того, чтобы системному администратору, который вошел в сеть под своей учетной записью, не предлагалось вводить пароль. Однако этот механизм доступа к сайту невозможен по неизвестным причинам. Рекомендуется не ставить эту галку.
Ðèñóíîê 8
35
администрирование temp=temp + "<MB> <Version> " + objItem.Version + ↵ " </Version>" + chr(10) temp=temp + "<Mbinfo> " + objItem.SMBIOSBIOSVersion + ↵ " </Mbinfo></MB>" + chr(10) + case 2 temp=temp + "<CPU> <Name> " + objItem.name + ↵ " </Name>" + chr(10) ' CPU name temp=temp + "<Description> " + objItem.Description + ↵ " </Description>" + chr(10) ' Description temp=temp + "<Socket> " + objItem.SocketDesignation + ↵ " </Socket></CPU>" + chr(10) ' Socket type case 3 if b=0 then temp=temp +"<Memory>" end if b=b+1 temp=temp+"<Device" + cstr(b) +">" temp=temp+" <Slot> " + objItem.DeviceLocator + " </Slot> " temp=temp+" <Capacity> " + objItem.Capacity + "</Capacity> " temp=temp+"</Device" + cstr(b) +">" case 4 if c=0 then temp=temp +"</Memory>" & chr(10) &"<Audio>" end if
Ðèñóíîê 9
Замечание Компания Microsoft утверждает, что корректно работать с WMI можно только пользователю с административными привилегиями. Практика показывает, что более 90% параметров корректно определяются при работе с WMI без наличия административных привилегий и привилегий опытного пользователя. Замечено, что для пользователя, не обладающего привилегиями, возникают проблемы при определении биоса материнской платы и характеристик жесткого диска. Возникшие проблемы решаются чтением соответствующих ветвей реестра с помощью VBScript или WSH. Пользователи, имеющие привилегии опытного пользователя на локальной машине, не испытывают никаких неудобств.
Приложение 1 Sysinfo.VBS dim strClass strClass=Array("Win32_ComputerSystem", "Win32_BIOS", ↵ "Win32_Processor", "Win32_PhysicalMemory", ↵ "Win32_SoundDevice", "Win32_VideoConfiguration", ↵ "Win32_NetworkAdapter", "Win32_USBController", ↵ "Win32_CDROMDrive", "Win32_DiskDrive", ↵ "Win32_LogicalDisk", "Win32_DiskPartition") Set objWMIService = GetObject("winmgmts://./Root\Cimv2") for a=0 to 11 Set colItems = objWMIService.InstancesOf(strClass(a)) For Each objItem in colItems select case a case 0 FileName=objItem.Name & "_Ïðèëîæåíèå1.xml" temp=temp + "<Computer><PCName>" + objItem.Name + ↵ "</PCName>" + chr(10) temp=temp + " <Domain> " + objItem.Domain + " ↵ </Domain>" + chr(10) temp=temp + "<User> " + objItem.Username + ↵ " </User>" + chr(10) temp = temp + "<Date>" + cstr(Date()) + "; ↵ " + cstr(Time()) + "</Date> </Computer>" + chr(10) case 1
36
c=c+1 temp=temp+"<Device" + cstr(c) + "> " temp=temp+"<Manufacturer> " + objItem.Manufacturer + ↵ " </Manufacturer> " temp=temp+"<Name> " + objItem.Name + " </Name> " temp=temp+"</Device" + cstr(c) + "> " case 5 if d=0 then temp=temp +"</Audio>" & chr(10) &"<Video>" end if d=d+1 temp=temp+"<Device" + cstr(d) + "><Type> " + ↵ objItem.AdapterType+ " </Type> " temp=temp+"<Memory> " + cstr(objItem.AdapterRAM) + ↵ "</Memory> " temp=temp+ "<Resolution>"+ ↵ cstr(objItem.HorizontalResolution)+ ↵ "x"+cstr(objItem.VerticalResolution)+ ↵ "x"+cstr(objItem.BitsPerPixel)+"@"+ ↵ cstr(objItem.RefreshRate)+"Hz</Resolution>" temp=temp+"</Device" + cstr(d) + "> " case 6 if e=0 then temp=temp +"</Video>" & chr(10) &"<NetCard>" end if e=e+1 if objItem.MacAddress<>"" then q=q+1 temp=temp+"<Device" + cstr(q) + "> ↵ <Manufacturer>"+objItem.Manufacturer+"</Manufacturer>" temp=temp+"<Name>"+objItem.Name+"</Name>" temp=temp+"<MAC>"+objItem.MacAddress+"</MAC> ↵ </Device" + cstr(q) + "> " end if case 7 if g=0 then temp=temp +"</NetCard>" & chr(10) & "<USB>" end if if objItem.Name<>"" then g=g+1 temp=temp + "<NameUSB" + cstr(g) +">" + objItem.Name + ↵ "</NameUSB" + cstr(g) +"> " + chr(10) ' USB Controller end if case 8 if h=0 then temp=temp +"</USB>" & chr(10) & "<CD-ROM>" end if if objItem.Caption<>"" then h=h+1 temp=temp + "<Device" + cstr(h) +"> <Model>" + ↵ objItem.Caption + " </Model>" + chr(10) ' Model temp=temp + "<Description>" + objItem.Description + ↵
администрирование " </Description>" + chr(10) ' Description temp=temp + "<Letter>" + objItem.Drive + " </Letter> ì </Device" + cstr(h) +"> " + chr(10) ' Letter end if case 9 if i=0 then temp=temp + "</CD-ROM>" & chr(10) & " <HDD>" end if i=i+1 temp=temp + "<Device" +cstr(i) +"> <Model>" + ↵ objItem.Caption + " </Model>" + chr(10) ' Model temp=temp + "<Description>" + objItem.Description + ↵ " </Description>" + chr(10) ' Description temp=temp + "<Size>" + cstr(objItem.Size) + ↵ " </Size>" + chr(10) ' Size of HDD temp=temp + "<Number>" + cstr(objItem.Index) + ↵ " </Number>" + chr(10) ' Number of HDD temp=temp + "<Partitions>" + cstr(objItem.Partitions) + ↵ " </Partitions> </Device" + cstr(i) +">" + ↵ chr(10)' Number of partitions case 10 if k=0 then temp=temp + "</HDD>" & chr(10) & " <Media>" end if k=k+1 temp=temp +"<Device" +cstr(k) +"> <Letter>" + ↵ objItem.Name + " </Letter>" + chr(10) ' Letter temp=temp + "<Description>" + cstr(objItem.Description) + ↵ " </Description>" + chr(10) ' Description if objItem.FileSystem<>"" then temp=temp + "<FullSize>" + objItem.Size + ↵ " </FullSize>" + chr(10) ' File System temp=temp + "<FreeSize>" + objItem.FreeSpace + ↵ " </FreeSize>" + chr(10) ' File System end if temp=temp +"</Device" + cstr(k) +"> " case 11 if l=0 then temp=temp + "</Media> " & chr(10) & "<Partition>" end if l=l+1 temp=temp + "<Device" + cstr(l) +"> <Name>" + ↵ objItem.Name + " </Name>" + chr(10) ' Model temp=temp + "<Size>" + cstr(objItem.Size) + " </Size> ↵ </Device" + cstr(l) +">" + chr(10) ' Number of partitions end select Next Next
AutoScript.VBS Set objNameSpace = GetObject("WinNT:") For Each Domain in objNameSpace strDomain Domain.Name Next Set Users_Domain = getobject("WinNT://" & strDomain) Users_Domain.Filter = Array("user") strGroup="Skip" strGroup = InputBox("Group:", "Skip users", "Skip") strScript="Script.bat" strScript=InputBox("Script:","Script Name", ↵ " Script.bat ") For each user in users_domain i=0 a=user.name Set user_group = GetObject("WinNT://" & ↵ strDomain & "/" & strGroup) For each user_group in ↵ user_group.Members b=user_group.name if b=a then i=1 end if next if i=0 then User.LoginScript=strScript User.setinfo End if Next
Приложение 2 Default.HTM <HTML> <HEAD> <!-- Ëåâûé ñòîëáåö ñîñòàâëÿåò 30% îò øèðèíû âñåãî îêíà. Ëåâîå îêíî èìååò èäåíòèôèêàòîð «main», âòîðîå «var». --> <TITLE>Ñïèñîê äîñòóïíûõ ñåòåâûõ ïðèíòåðîâ </TITLE> <META HTTP-EQUIV ="Content-Type" CONTENT="text/html; ↵ CHARSET=windows-1251"> </HEAD> <!-- Åñëè ïàðàìåòð sort=1, îñóùåñòâëÿåòñÿ ñîðòèðîâêà ïî íàçâàíèþ ðàáî÷èõ ñòàíöèé, åñëè sort=2 – ñîðòèðîâêà èäåò ïî èìåíè ïîëüçîâàòåëÿ». --> <FRAMESET cols="30%,*" FRAMEBORDER="5" BORDER="yes" ↵ FRAMESPACING="5" > <FRAME SRC="xml_list.asp?sort=1&Search_Text=""" ↵ NAME="xml" SCROLLING="yes" ÌÀRGINHEIGHT=1 > <FRAME SRC ="about:blank" NAME="var"> </FRAMESET > </HTML>
temp=temp + "</Partition>" Set fso = CreateObject("Scripting.FileSystemObject") Set f = fso.OpenTextFile(FileName, 2, True) f.Write "<inf>" & temp & "</inf>" f.Close msgbox "end"
Script.BAT @ECHO OFF if c:\%os%==c:\ goto win9x if not c:\%os%==c:\ goto winnt :winnt @echo Ïîäîæäèòå! Âûïîëíÿåòñÿ íàñòîéêà Âàøåãî êîìïüþòåðà. start /wait sysinfo.vbs goto end :win9x @echo windows 9x %0\..\Script. sysinfo.vbs goto end :end @echo End Of Batch File
№12(13), декабрь 2003
Stylet.CSS H4 {font-size:11; font-family:Arial;} H5 {font-size:10; font-family:Arial;} H6 {font-size:9; font-family:Arial;}
Xml_List.ASP <%@ Language=VBScript CODEPAGE=1251%> <HEAD> <LINK href="style.css" type=text/css rel=stylesheet> <meta http-equiv="Content-Type" content="text/html" ↵ charset=windows-1251> <meta http-equiv="refresh" content=10 > </HEAD> <BODY> <H4><b><center>"Èíôîðìàöèÿ î ðàáî÷èõ ↵ ñòàíöèÿõ"</center></H4> <br> <h6> <FORM ACTION="xml_list.asp" target="xml" METHOD="get"> <INPUT TYPE="submit" VALUE="Ïîèñê"></INPUT> <INPUT NAME="Search_Text"></INPUT> </FORM> </h6>
37
администрирование <%set search_var = Request.QueryString("Search_Text") set sort_var = Request.QueryString("sort")
else
path="\\server\folder" Set a=CreateObject("Wscript.Shell") Set fso=CreateObject("Scripting.FileSystemObject") Set oFolder=fso.GetFolder(a.ExpandEnvironmentStrings(path)) Set oFiles=oFolder.Files set xmlVisitor=server.CreateObject("Microsoft.XMLDOM") dim array_pcname() dim array_username() dim array_sort() dim array_filename() redim preserve array_pcname(oFiles.count) redim preserve array_username(oFiles.count) redim preserve array_sort(oFiles.count) redim preserve array_filename(oFiles.count) size_array=ubound(array_sort) i=0 For each oFile in oFiles XMLFile=xmlVisitor.load(server.MapPath(path ↵ & oFile.Name)) With xmlVisitor.documentElement UN=.childNodes(0).childNodes(2).text array_filename(i)=oFile.Name array_pcname(i)=.childNodes(0).childNodes(0).text array_username(i)=right(UN, len(UN)-instr(UN,"\")) i=i+1 End With next
Analyse.ASP <%@ Language=VBScript CODEPAGE=1251%> <HEAD> <LINK href="style.css" type=text/css rel=stylesheet> <meta http-equiv="Content-Type" content="text/html" ↵ charset=windows-1251>
if search_var="" then select case sort_var case 1 for i=0 to size_array array_sort(i) = array_pcname(i) next case 2 for i=0 to size_array array_sort(i) = array_username(i) next end select
</HEAD> <%set path=Request.QueryString("fn") set xmlVisitor=server.CreateObject("Microsoft.XMLDOM") XMLFile=xmlVisitor.load(server.MapPath(path)) With xmlVisitor.documentElement
on error resume next for j=0 to size_array for i=0 to size_array if strcomp(array_sort(i),array_sort(i+1),0)=1 then temp=array_sort(i) array_sort(i)=array_sort(i+1) array_sort(i+1)=temp temp=array_pcname(i) array_pcname(i)=array_pcname(i+1) array_pcname(i+1)=temp temp=array_pcname(i) array_pcname(i)=array_pcname(i+1) array_pcname(i+1)=temp temp=array_filename(i) array_filename(i)=array_filename(i+1) array_filename(i+1)=temp end if next next for i=0 to size_array-1 select case sort_var case 1 response.write "<a href=analyse.asp?FN=" & fname & array_filename(i+1) & "&Sort=" sort_var & " target=""analyse"" ↵ title=""Èìÿ ïîëüçîâàòåëÿ - " & ↵ array_username(i) &""" a>" & ↵ array_pcname(i) &"</a><BR>" case 2 response.write "<a href=analyse.asp?FN=" & fname & array_filename(i+1) & "&Sort=" sort_var & " target=""analyse"" ↵ title=""Ðàáî÷àÿ ñòàíöèÿ - " & ↵ array_pcname(i) &""" a>" & ↵ array_username(i) &"</a><BR>" end select next
38
Response.Write "<table width=""100%"", Cellpacing=""0"">" Response.Write "<TR><TD width=150><H4> Ðåçóëüòàòû ïîèñêà ↵ ïî </H4></TD><TD> <H6>" & search_var & "</H6></TD></TR>" Response.Write "<table width=""100%"", Cellpacing=""0"">" For each oFile in oFiles XMLFile=xmlVisitor.load(server.MapPath(path ↵ & oFile.Name)) With xmlVisitor.documentElement for i=0 to .childNodes.length-1 if instr(Lcase(.childNodes(i).text),LCase(search_var)) then Response.Write " <TR> <TD width=50><H6><a ↵ href=analyse.asp?FN=" & fname & ↵ ofile.name & " target=""analyse"">" & ↵ left(oFile.Name,len(oFile.Name)-4)& " ↵ </a> </TD><H6> <TD><H6>" & ↵ .childNodes(i).text & "</TD><H6></TR>" end if next End With next Response.Write "</Table>" end if set xmlVisitor=Nothing %>
↵ & ↵
↵ & ↵
Response.Write "<H4> Ðàáî÷àÿ ñòàíöèÿ</H4> ↵ <table width=""100%"", Cellpacing=""0"">" Response.Write " <TR> <TD width=300><H6> Ðàáî÷àÿ ñòàíöèÿ ↵ </TD><H6> <TD width=300><H6>" & ↵ .childNodes(0).childNodes(0).text & "</TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> Ïîëüçîâàòåëü ↵ </TD><H6> <TD width=300><H6>" & ↵ .childNodes(0).childNodes(2).text & "</TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> Äîìåí </TD><H6> ↵ <TD width=300><H6>" & ↵ .childNodes(0).childNodes(1).text & "</TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> Äàòà ðåãèñòðàöèè ↵ â ñåòè</TD><H6> <TD width=300><H6>" & ì .childNodes(0).childNodes(3).text & "</TD><H6></TR>" Response.Write "</Table>" Response.Write "<H4> Ìàòåðèíñêàÿ ïëàòà, ïðîöåññîð, ↵ ïàìÿòü</H4> <table width=""100%"", Cellpacing=""0"">" Response.Write " <TR> <TD width=300><H6> Ìàòåðèíñêàÿ ïëàòà ↵ </TD><H6> <TD width=300><H6>" & ↵ .childNodes(1).childNodes(1).text & "</TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> Ìîäåëü BIOS ↵ </TD><H6> <TD width=300><H6>" & ↵ .childNodes(1).childNodes(0).text & "</TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> Ïðîöåññîð ↵ </TD><H6> <TD width=300><H6>" & ↵ .childNodes(2).childNodes(0).text & "</TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> Ïîêîëåíèå ↵ </TD><H6> <TD width=300><H6>" & ↵ .childNodes(2).childNodes(1).text & "</TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> Ðàçúåì ïðîöåññîðà ↵ </TD><H6> <TD width=300><H6>" & ↵ .childNodes(2).childNodes(2).text & "</TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> Ñëîò è òèï RAM ↵ </TD><H6> <TD width=300><H6>" & ↵ .childNodes(3).childNodes(0).childNodes(0).text & ↵ "</TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> Ðàçìåð, Ìá ↵ </TD><H6> <TD width=300><H6>" & ↵ .childNodes(3).childNodes(0).childNodes(1).text/(1000*1000) ↵ & "</TD><H6></TR>" Response.Write "</Table>"
администрирование Response.Write "<H4> Æåñòêèå äèñêè</H4> ↵ <table width=""100%"", Cellpacing=""0"">" q=9 for i=0 to .childNodes(q).childNodes.length-1 Response.Write " <TR> <TD width=300><H6> <i>" & ↵ .childNodes(q).childNodes(i).childNodes(1).text & ↵ i+1 & "</i></TD><H6><TD width=300><H6>" & ↵ .childNodes(q).childNodes(i).childNodes(0).text & ↵ "</TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> Ðàçìåð, Ãá ↵ </TD><H6> <TD width=300><H6>" & ↵ round(.childNodes(q).childNodes(i).childNodes(2). ↵ text/(1000*1000*1000),1) & "</TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> ↵ Ëîãè÷åñêèõ ðàçäåëîâ</TD><H6> <TD width=300><H6>" & ↵ .childNodes(q).childNodes(i).childNodes(4).text & ↵ "</TD><H6></TR>" next Response.Write "</Table>" Response.Write "<H4> CD-ROM</H4> <table width=""100%"", ↵ Cellpacing=""0"">" q=8 for i=0 to .childNodes(q).childNodes.length-1 Response.Write " <TR> <TD width=300><H6>" & ↵ .childNodes(q).childNodes(i).childNodes(1).text & ↵ i+1 & "</TD><H6><TD width=300><H6>" & ↵ .childNodes(q).childNodes(i).childNodes(0).text & ↵ "</TD><H6></TR>" next Response.Write "</Table>" Response.Write "<H4> Çâóêîâàÿ ïëàòà</H4> ↵ <table width=""100%"", Cellpacing=""0"">" q=4 for i=0 to .childNodes(q).childNodes.length-1 Response.Write " <TR> <TD width=300><H6> <i> Àäàïòåð" & ↵ i+1 & "</i> </TD><H6> <TD width=300><H6></TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> Ïðîèçâîäèòåëü ↵ </TD><H6> <TD width=300><H6>" & ↵ .childNodes(q).childNodes(i).childNodes(0).text & ì "</TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> Ìîäåëü ↵ </TD><H6> <TD width=300><H6>" & ↵ .childNodes(q).childNodes(i).childNodes(1).text & ↵ "</TD><H6></TR>" next Response.Write "</Table>" Response.Write "<H4> Ãðàôè÷åñêèé àäàïòåð</H4> ↵ <table width=""100%"", Cellpacing=""0"">" q=5
№12(13), декабрь 2003
for i=0 to .childNodes(q).childNodes.length-1 Response.Write " <TR> <TD width=300><H6><i> Àäàïòåð ↵ </i>" & i+1 & "</TD><H6> <TD width=300><H6></TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> Ìîäåëü ↵ </TD><H6> <TD width=300><H6>" & ↵ .childNodes(q).childNodes(i).childNodes(0).text & ↵ "</TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> Ïàìÿòü, Ìá ↵ </TD><H6> <TD width=300><H6>" & ↵ .childNodes(q).childNodes(i).childNodes(1). ↵ text/(1000*1000) & "</TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> ↵ Õàðàêòåðèñòèêè ýêðàíà </TD><H6> <TD width=300><H6>" & ↵ .childNodes(q).childNodes(i).childNodes(2).text & ↵ "</TD><H6></TR>" next Response.Write "</Table>" Response.Write "<H4> Ñåòåâîé àäàïòåð</H4> ↵ <table width=""100%"", Cellpacing=""0"">" q=6 for i=0 to .childNodes(q).childNodes.length-1 Response.Write " <TR> <TD width=300><H6> <i> Àäàïòåð ↵ </i>" & i+1 & "</TD><H6> <TD width=300><H6></TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> Ïðîèçâîäèòåëü ↵ </TD><H6> <TD width=300><H6>" & ↵ .childNodes(q).childNodes(i).childNodes(0).text & ↵ "</TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> Ìîäåëü ↵ </TD><H6> <TD width=300><H6>" & v .childNodes(q).childNodes(i).childNodes(1).text & ↵ "</TD><H6></TR>" Response.Write " <TR> <TD width=300><H6> ÌÀÑ-àäðåñ ↵ </TD><H6> <TD width=300><H6>" & ↵ .childNodes(q).childNodes(i).childNodes(2).text & ↵ "</TD><H6></TR>" next Response.Write "</Table>" Response.Write "<H4> USB </H4> <table width=""100%"", ↵ Cellpacing=""0"">" q=7 for i=0 to .childNodes(q).childNodes.length-1 Response.Write " <TR> <TD width=300><H6> Ïîðò " & i+1 & ↵ " </TD><H6> <TD width=300><H6>" & ↵ .childNodes(q).childNodes(i).childNodes(0).text & ↵ "</TD><H6></TR>" next Response.Write "</Table>" End With set xmlVisitor=Nothing%>
39
администрирование
КРЕПОСТЬ ДЛЯ ПИНГВИНА
СЕРГЕЙ ЯРЕМЧУК 40
администрирование Сегодня, как никогда, особое внимание уделяется защите серверов и персональных компьютеров от вторжения извне. Описание различных методов атак можно найти практически везде, у нападающего способов пробраться в чужой компьютер немало, да и с желающими также проблем обычно не бывает. Но сисадмину или обычному пользователю от этого не легче, все больше и больше приходится уделять времени чтению документации, настройке системы, но время, как правило, не на стороне обороняющегося, да и опыт приходит вместе с ошибками. Ситуация усугубляется тем, что производители в последнее время выпускают дистрибутивы по типу «два в одном», которые могут быть с одинаковым успехом установлены как на сервер, так и на персональный компьютер, причем, по моему мнению, все равно, для того чтобы привлечь большее количество народа, упор делается все-таки на последний. А пользователю главное – удобство, естественно, оно достигается и путем уменьшения требований к защите. Что делать в таком случае? Не ждать же в самом деле, пока сисадмин будет готов к выходу в Интернет. Можно, конечно, пойти на курсы, может, и научат, но фактор времени остается. Существует множество различных утилит, так или иначе предназначенных для улучшения защиты Linux-системы, в данной статье хочу обратить внимание на проект Bastille Linux, домашняя страница которого находится по адресу: http://www.bastille-linux.org/. Помимо главной задачи – укрепление установленной системы – разработчики Bastille Linux преследовали и другие не менее важные цели: всесторонность – все, что описано в открытых источниках по поводу усиления защиты Linux, нашло свою реализацию Bastille Linux. В основу легли разработки Джея Била (Jay Beale) по укреплению Solaris и Linux, нашедших свое отражение в книге института SANS (SysAdmin, Audit, Network, Security) «Securing Linux Step by Step», руководство Курта Сеифриеда (Kurt Seifried) Linux Administrator’s Security Guide Linux (http:// www.seifried.org/lasg/) и другие источники; поучительность – Bastille Linux был разработан также с целью обучить администратора проблемам в защите, включенным в каждую из задач сценария. Каждый необязательный шаг содержит описание включенных проблем безопасности; сообщество – после того как были сделаны начальные разработки, было создано сообщество разработчиков, которое совместными усилиями вносило изменение в Bastille. При помощи программы настройки Bastille Linux с целью улучшения общей безопасности настраиваются демоны, изменяются некоторые системные параметры и firewall. Дополнительно (при необходимости) отключаются ненужные сервисы вроде печати, rcp и rlogin. С ее помощью можно создать среду «chroot jails», при помощи которой можно уменьшить уязвимость некоторых интернет-сервисов вроде Web и DNS. В настоящее время поддерживаются следующие дистрибутивы и системы RedHat, Debian, Mandrake, SuSE и TurboLinux, а также HP-UX и Mac OS X (поддержка последней добавилась совсем недавно).
№12(13), декабрь 2003
Установка При закачке необходимо по ссылке выбрать пакет для используемого дитсрибутива или исходные тексты для предпочитающих устанавливать из исходников. Кроме этого потребуется интерпретатор Perl версии не ниже 5.6.1 и для интерактивного режима потребуются на выбор: для ease-of-use X-Window Perl/Tk версии не ниже 800.23 (версия для RedHat: ftp://ftp.redhat.com/pub/redhat/linux/7.1/en/ DMA/CPAN/RPMS/perl-Tk-800.022-11.i386.rpm) и для текстового режима (recommended for high security) Perl/Curses версии 1.06 и выше (ftp://ftp.redhat.com/pub/redhat/linux/7.1/ en/DMA/CPAN/RPMS/perl-Curses-1.05-10.i386.rpm). Для установки при помощи rpm-пакетов необходимо ввести все те же rpm -iv, а при установке из исходников после распаковки архива заходим внутрь образовавшегося каталога и вводим ./Instal.sh. После чего программа скопирует все файлы на свои места и установит необходимые для работы модули Perl. Теперь можно запускать. Как уже говорил, программа может использоваться двумя способами: в интерактивном режиме и в неинтерактивном. В интерактивном режиме интерфейс пользователя позволяет объяснить системному администратору проблемы в защите и попутно позволяет их решить. Этот подход удобен тем, что, с одной стороны, защищает систему, а с другой – обучает на конкретных примерах. Неинтерактивный режим позволяет использовать уже готовые файлы конфигурации, изготовленные в интерактивном режиме для изменения параметров на других системах, что позволяет избегать повторного прохождения всех этапов, т.к. для того, чтобы спокойно и обдуманно ответить на все вопросы, потребуется отвести приличное время. При этом программа должна быть запущена каждый раз после установки нового ПО или установки патча (для RedHat http://www.redhat.com/apps/support/errata/), которые могли повлиять на ослабление защиты. Также могут быть случаи, когда применение Bastille может вызвать побочный эффект, когда блокируются ни в чем не повинные программы, поэтому все-таки перед применением на рабочем компьютере поэкспериментируйте на тестовом. Запустить программу конфигурации в интерактивном режиме можно двумя способами. Первый состоит в запуске perl-скрипта InteractiveBastile, по умолчанию или с указанием дополнительного аргумента -х, используется Tkинтерфейс, требующий запуска Х-Window, что проверяется установленным значением переменной $DISPLAY. При этом всегда можно вернуться к предыдущему пункту, что позволяет использовать выборочную конфигурацию, для удобства обладающую статус-баром, позволяющим оценить «пройденное расстояние». Если же система используется, например, на роутере и не имеет установленной системы Х-Window, то с заданием ключа -с, bastille будет запущен с текстовым интерфейсом Perl/Curses. Но этим способом, описанным в инструкции, не всегда удается запустить программу. Поэтому в таком случае можно воспользоваться вторым вариантом, вызов bastille напрямую. # /usr/sbin/bastille
Ключи для выбора интерфейса в этом случае аналогичны предыдущим.
41
администрирование Иногда программа не может узнать, в каком дистрибутиве она установлена, и начинает ругаться, приводя длинный список «совместимых». Could not determine operating system version! Bastille does not work on this OS: unknown Currently, Bastille works on the following: DB2.2 DB3.0 RH6.0 RH6.1 RH6.2 RH7.0 RH7.1 RH7.2 RH7.3 RH8.0 RH9 MN6.0 MN6.1 MN7.0 MN7.1 MN7.2 MN8.0 MN8.1 HP-UX11.00 HP-UX11.11 HP-UX11.22 HP-UX11.23 SE7.2 SE7.3 SE8.0 TB7.0 OSX10.2.0 OSX10.2.1 OSX10.2.2 OSX10.2.3 OSX10.2.4
Для того чтобы все-таки уговорить ее работать, задаем при помощи ключа –os название дистрибутива, выбрав сокращенное название из приведенного выше списка (только при первом запуске). # /usr/sbin/bastille –os
RH8.0
И в результате появится окно, представленное на рисунках. Выбрав интересуемую категорию, начинаем отвечать на вопросы, в большинстве пунктов ответом будет выбор из двух вариантов – Yes или No, но, например, при вводе диапазонов портов дополнительно активируется внизу экрана полоса «Answer», куда и следует вводить данные. При ответе на вопросы можно использовать кнопку «Explain More/Explain Less» для более или менее подробного объяснения, правда, для некоторых пунктов доступен только один из вариантов подсказок. К сожалению, русификацией Bastille Linux еще никто не занимался, поэтому, чтобы разобраться в вопросах, необходимо знание английского (оптом вопросы можно просмотреть, ознакомившись с файлом Questions.txt). После ответа на все вопросы в последнем пункте сохраняем конфигурацию.
42
Для неинтерактивного режима первоначально проделываем все вышеописаное, для того чтобы содать необходимые файлы конфигурации, все ответы на вопросы находятся в /etc/Bastille/config. После этого устанавливаем Bastille на каждую машину с такой же самой операционной системой, как и та, в которой он был сделан. И вводим на каждой: # /usr/sbin/bastille -b
При этом могут возникнуть и ошибки. Чтобы просмотреть информацию об изменяемых параметрах для всех систем разом, введите: # tail -f /var/log/Bastille/action-log
или вывод ошибок: # tail -f /var/log/Bastille/error-log
Дополнительно в файл /var/log/Bastille/TODO система заносит оставшиеся действия, которые система не может выполнить автоматически и их пользователь должен выполнить вручную (например, перезагрузка сервисов). Возврат к предыдущему (до Bastill) состоянию можно осуществить при помощи опции -r (revert) или запуском отдельного скрипта RevertBastille. # /usr/sbin/bastille -r
При этом удаление самой программы Bastille без выполнения этого действия не приведет к автоматическому откату.
администрирование
Пользователю придется ответить не на один десяток вопросов, чтобы иметь представление об основных разделах программы. При этом разделы, которые касаются только одной из систем, помечены как HP-UX only или Linux only. Пару слов о PSAD. Эта программа, написанная на Perl (http://www.cipherdyne.com), использует программы firewall для анализа сканирования портов и методы обнаружения сигнатур, используемые в Snort Intrusion Detection System (http://www.snort.org). При этом обнаруживается большинство различных методов сканирования. Все интересные события регистрируются при помощи syslog. Как видите, Bastille Linux представляет собой легкий в использовании, удобный и интуитивно понятный инструмент, позволяющий существенно поднять защищенность компьютера, будь то сервер или десктоп. И дополнительно является неплохим пособием по изучению защиты Linux-систем. Удачи.
№12(13), декабрь 2003
43
администрирование
УЧЕТ РАБОТЫ DIALUP-ПОЛЬЗОВАТЕЛЕЙ В СИСТЕМЕ FreeBSD
СЕРГЕЙ СУПРУНОВ
44
администрирование Если вы вознамерились стать провайдером услуг Интернета, имея сервер под управлением FreeBSD и несколько модемов на входе, то одной из первых задач, которая встанет перед вами, будет проблема учета времени работы ваших пользователей. Безусловно, существует целый ряд готовых программных продуктов, в той или иной степени решающих задачу учета (и тарификации) работы пользователей, выходящих в Интернет через модемный пул сервера. Однако для «частного» использования вряд ли целесообразно «прикручивать» к вашей системе RADIUS или что-то подобное. В данной статье мы попытаемся рассмотреть общие принципы решения задачи учета работы «дайлапников», скажем так, подручными средствами. Конкретную реализацию оставим за рамками данной статьи. Итак, для того чтобы посчитать время работы пользователя, мы должны решить три задачи: определение момента входа пользователя в систему, определение момента выхода из системы и сохранение информации о данном соединении для последующего использования. Если мы изберем авансовую систему оплаты доступа (когда «утром деньги – вечером стулья»), то потребуется также контролировать состояние счета абонента в процессе его работы, и отключать его, если аванс на его счету будет исчерпан. Также может потребоваться и учет потребленного трафика. Поскольку мы не ставим своей задачей разработку серьезной и универсальной системы, то будем стремиться максимально использовать то, что у нас уже есть. Также мы не будем связываться с программированием, чтобы основная идея не затерялась в дебрях алгоритмизации, а ограничимся скромными скриптами на Shell и Perl. Посмотрим, какие «встроенные» средства учета нам доступны. Прежде всего это wtmp – файл, в котором хранится информация о последних соединениях. Просмотреть содержащуюся в нем информацию можно командой last. Как видно, используя эту команду, можно получить подробную информацию о моментах входа-выхода пользователя в систему и о продолжительности соединения (last с ключом -s (last -s) отображает продолжительность соединения в секундах) за период с момента последней ротации (перезаписи) файла wtmp. Период ротации выбирается в зависимости от нагрузки на систему и задается с таким расчетом, чтобы его размер не достигал катастрофических значений. Учитывая, что мы рассматриваем небольшую систему, обновлять файл wtmp достаточно ежемесячно (cкрипт, производящий обновление, в этом случае скорее всего будет располагаться в /etc/periodic/ monthly). Второй важный инструмент, который нам понадобится – команда who, которая выводит информацию о пользователях, подключенных к системе в данный момент. Любители языка Си могут воспользоваться файлом utmp, из которого информация о текущих подключениях и черпается. С остальными вспомогательными средствами познакомимся в процессе рассмотрения конкретных методов учета.
№12(13), декабрь 2003
Итак, для начала рассмотрим способы, которыми можно определить момент входа пользователя в систему. В простейшем случае, когда информация о работе пользователей нужна нам «задним числом», вполне достаточно будет анализа данных, возвращаемых командой last. Например, в конце месяца мы можем просто просуммировать продолжительность соединений для каждого пользователя, и выставить счета на основе этой информации (простейший скрипт lastreader.pl, выполняющий данную функцию, представлен на вкладке). lastreader.pl: #!/usr/bin/perl –w # îòêðûâàåì last íà ÷òåíèå open(LAST, ‘last -s|’) || die ‘Error’; while(<LAST>) { chomp; if($_) { # âûäåëÿåì èìÿ ïîëüçîâàòåëÿ è óñòðîéñòâî ($user, $tty) = split(/\s/); # Äàëåå îáðàáàòûâàåì òîëüêî ìîäåìíûå ñîåäèíåíèÿ ttydX if($tty =~ /ttyd/) { # âûäåëÿåì çíà÷åíèå â ñêîáêàõ – ïðîäîëæèòåëüíîñòü # ñîåäèíåíèÿ â ñåêóíäàõ $_ =~ s/\(\s*(\d+)\)/$1/g; if(($user)&&($1) { # ñóììèðóåì ïðîäîëæèòåëüíîñòè ïî ïîëüçîâàòåëÿì $totals{$user} += $1; } } } } close(LAST); # ñîðòèðóåì ïî àëôàâèòó ïîëüçîâàòåëåé @res = sort keys %totals; foreach $item (@res) { # âûâîäèì ðåçóëüòàò íà ýêðàí print “$item - $totals{$item}\n”; } exit(1);
Или обрабатывать эту информацию ежедневно, сохраняя результаты в свои файлы. Однако такой способ учета не позволяет контролировать текущее состояние счета абонента с тем, чтобы не допустить превышения установленного лимита (или округляет такой контроль до суток, например). Также если нам нужно блокировать работу определенных пользователей без изменения информации в системных файлах, то определять вход пользователя нужно в режиме реального времени. Одним из самых очевидных способов является просмотр списка находящихся в данный момент в системе пользователей. Например, если запускать команду who каждые пять секунд, то мы сможем определить появление в системе пользователя с точностью до этого значения. Присутствие в системе пользователя можно определить и по команде last – подключенные в данный момент абоненты отмечены как «still logged in». Однако рассмотренный выше способ чреват нерациональным расходом ресурсов (постоянные вызовы «левых» программ даром не проходят) и точностью, ограниченной периодом вызова вспомогательных команд. Чтобы определить более элегантный способ, рассмотрим процесс входа в систему с модемного пула. В данной статье остановимся на рассмотрении двух способов входа в систему – pap- и login-аутентификации. В первом случае последовательность такова:
45
администрирование после того, как модемы установят соединение, конк
ретное ttyd-устройство сопоставляется с интерфейсом pppX; запускается демон pppd, обслуживающий данное соединение; выполняется pap-аутентификация пользователя; отрабатывается скрипт auth-up (если есть), как правило, располагающийся в /etc/ppp; отрабатывается скрипт ip-up (если есть), располагающийся там же, где и auth-up. Скрипт ip-up вызывается со следующими параметрами: ip-up interface-name tty-device speed local-IP remote-IP ipparam
где: interface-name – имя интерфейса pppX, tty-device – устройство tty, через которое осуществляется соединение, speed – скорость на порту (на tty-устройстве), local-IP, remote-IP – соответственно локальный и удаленный IP-адреса, ipparam – дополнительные параметры. Для нас интерес представляют первые два параметра, передаваемые в скрипт. К сожалению, имя пользователя в ip-up не передается, и мы можем узнать только о том, что какой-то пользователь выполнил подключение. Параметры вызова скрипта auth-up следующие: auth-up interface-name peer-name user-name tty-device speed
где: interface-name – имя интерфейса pppX, peer-name – имя пользователя, установившего соединение, user-name – пользователь, с чьими правами запущен pppd (как правило, root), tty-device – устройство tty, через которое осуществлено соединение, speed – скорость на порту (на tty-устройстве). В данном случае, как видно, в скрипт передается еще один полезный параметр – имя авторизованного пользователя. Таким образом, мы можем сразу установить факт входа в систему конкретного абонента. Небольшая неприятность появляется в случае loginаутентификации (например, при входе в систему через стандартный скрипт). Если в качестве стандартной оболочки пользователю задать pppd, то процесс входа в систему будет следующим: после того, как модемы установят соединение, конкретное ttyd-устройство сопоставляется с интерфейсом pppX; проводится login-аутентификация; запускается программа, указанная в /etc/passwd как стандартная оболочка (в нашем случае это демон pppd); отрабатывается скрипт ip-up (если есть), как правило, располагающийся в /etc/ppp.
46
Поскольку аутентификация уже выполнена, то средствами pppd она не осуществляется, и потому скрипт authup не отрабатывается. Таким образом, если мы попытаемся использовать для регистрации входа пользователя в систему именно его, то при login-аутентификации пользователь зарегистрирован не будет. Поэтому, если мы хотим оставить пользователю возможность устанавливать соединение и через стандартный скрипт (с помощью loginаутентификации), то для определения его входа в систему нам остается только скрипт ip-up, который отрабатывается в любом случае. Однако теперь мы знаем только устройство, через которое пользователь подключен, и нам придется сопоставить устройство с конкретным пользователем самим. Для этого нам как раз и пригодится команда who (например, имя пользователя возвратит следующая команда: who | grep “ttydX” | awk ‘{print $1;}’
где «Х» – номер нужного нам ttyd-устройства). Вторая задача – определение момента, когда пользователь покидает систему, – решается аналогично. Это может быть либо проверка подключенных пользователей периодическим вызовом who, либо использование скриптов ip-down и auth-down. Первый отрабатывается при выходе из системы пользователя, вошедшего через papаутентификацию (для которого отрабатывался скрипт auth-up), второй – при завершении сеанса связи. Однако нужно иметь в виду, что в некоторых случаях «down-скрипты» могут не отрабатываться, например, при аварийной перезагрузке системы. Особо нужно отметить, что вышеописанные ppp-скрипты исполняются с правами суперпользователя (root). С одной стороны, это хорошо, поскольку позволяет нам совершать любые действия, но с другой – требует особой осторожности и аккуратности. Также не забывайте поддерживать права доступа к данным файлам как r-x-----(на стадии отладки можно поставить rwx------, но потом возможность записи необходимо снять). Сохранение статистической информации проблем вызвать не должно. Если мы знаем, когда пользователь вошел в систему и когда ее покинул, то достаточно просто сохранить эту информацию в файл или базу данных. Выбор конкретного формата (база MySQL, единый текстовый файл, индивидуальные файлы для хранения статистики по каждому пользователю) оставим на совести администратора. Теперь несколько слов о том, как можно определить обнуление счета абонента в процессе работы и соответственно дальнейшую работу оного пресечь самым жестоким образом. Основных способов здесь тоже два – постоянный (периодический) контроль остатка, и предварительное вычисление остатка. В первом случае специальный скрипт должен время от времени определять остаток на счете пользователя (который можно хранить в БД или текстовом файле), вычитать из него стоимость наработки на текущий момент и в случае отрицательной разности давать команду на отключение пользователя. Суть второго способа заключается в следующем: при входе
администрирование пользователя в систему определяется остаток на его счете и вычисляется время, которое абоненту хватит с данной суммой при действующем тарифе. Затем дается задание планировщику (это может быть как специально разработанный скромный скрипт, так и системная команда at) отключить данного пользователя через данное время. Естественно, нужно предусмотреть ситуацию, когда пользователь отключится добровольно: в этом случае нужно давать отмену планировщику, как только будет обнаружено отсутствие пользователя в системе, а также программа-киллер (которая будет заниматься черным делом отключения пользователя) должна уметь определять, нуждаются ли еще в ее услугах. Первое нужно, чтобы избежать накапливания сотен заданий на отключение пользователя через дни и месяцы, в то время как он уже давно пьет пиво вдали от родного Интернета, второе – для исключения банальных ошибок. Для принудительного завершения работы пользователя рекомендуется использовать утилиту killpppd (для FreeBSD ее можно найти в коллекции портов). Принимая в качестве параметров peer-name и tty-device, утилита осуществляет корректное завершение работы всех процессов, связанных с данным устройством. Если нам нужно еще и учитывать трафик, потребляемый пользователем, то самый простой вариант – использовать для этих целей ipfw (брандмауэр, входящий в состав FreeBSD). При входе пользователя в систему запускаем подсчет трафика на конкретном устройстве (если точнее, то подсчет трафика запускается на IP-адрес, однако определить адрес, присвоенный устройству, как правило, проблемой не является): ipfw add 10000 count ip from any to 100.100.100.5 out
Приведенная выше строка заставит брандмауэр считать входящий интернет-трафик («out» говорит о том, что будет учитываться трафик, исходящий из FreeBSD по направлению к клиенту, для клиента этот трафик будет соответственно входящим), приходящий на адрес 100.100.100.5 с любого источника. 10000 – номер правила, которое назначается для данной операции. Естественно, для каждого соединения нужно будет назначать свободный в данный момент номер правила (правила с одинаковым номером также будут корректно работать, но при удалении одного из них возникнут проблемы).
№12(13), декабрь 2003
Затем, когда пользователь отключается, считываем его наработку (ipfw show 10000) и удаляем правило (ipfw delete 10000). А наработку, соответственно пишем в файлик для последующего предъявления. Обобщая сказанное, можно сделать вывод, что встроенных средств FreeBSD вполне достаточно, чтобы за ночь «на коленке» написать биллинговую систему для обслуживания нескольких десятков пользователей. Если нам нужны только сведения о том, сколько пользователь провел времени в Сети за месяц, оптимальным будет обработка результата, выдаваемого по last –s. Если мы предоставляем доступ в Интернет только с использованием ppp-аутентификации (например, pap), то для определения входа пользователя в систему вполне может служить скрипт auth-up. Если наш сервер будет поддерживать и login-аутентификацию, то придется использовать скрипт ip-up. В этом случае имя пользователя придется определять вручную, основываясь на сведениях, предоставляемых командой who. Эту же команду, видимо, придется использовать и для определения момента отключения пользователя, поскольку метод, связанный со скриптами ip-down и auth-down, слишком ненадежен. Хотя в целях экономии ресурсов можно использовать комбинацию этих методов: отключение производить по команде соответствующего скрипта, но выполнять контроль по команде who через относительно большой промежуток времени (например, раз в 5 минут). Конечно, для построения эффективной, точной и надежной системы учета придется прибегнуть к программированию на С, однако в большинстве случаев концепция остается прежней – контроль файлов wtmp (last) и utmp (who).
Дополнительные материалы: 1. man last(1) – команда last; 2. man who(1) – команда who; 3. man grep(1), man awk(1) – команды обработки текстовых строк; 4. man at(1) – отложенное выполнение команды; 5. man pppd(8) – информация по auth-up, ip-up, auth-down, ip-down; 6. man ipfw(8) – информация по ipfw, в том числе по подсчету трафика; 7. man periodic(8) – дополнительные сведения по ротации wtmp; 8. man utmp(5) – обработка utmp на С; 9. man wtmp(5) – обработка wtmp на С.
47
администрирование
АНДРЕЙ БЕШКОВ 48
администрирование Как обычно, в начале статьи хотелось бы упомянуть то обстоятельство, что описываемые действия выполнялись на хосте, работающем под управлением FreeBSD 4.8. Переживать по этому поводу не стоит, так как все обсуждаемые приемы будут отлично работать с любым дистрибутивом Unix-подобных операционных систем, для которых существует версия Nagios. Единственным щекотливым моментом может быть различие в именах директорий, где расположились Nagios и остальное вспомогательное программное обеспечение, необходимое для нашей работы. Первым делом хотелось бы научить Nagios «говорить» на чистом русском языке. Примерно девять месяцев назад я завершил работы по локализации Nagios версии 1.06 beta. Затем, по мере выхода новых версий продукта, та же судьба постигла официальные релизы 1.0 и 1.1. Методика русификации для всех версий одинакова, поэтому я буду описывать ее на примере версии 1.1 как наиболее свежей и, надеюсь, наиболее распространенной. Итак, что же нам нужно сделать? Первым делом скачиваем дистрибутив версии Nagios, которая установлена у вас с официального сайта http://www.nagios.org. Здесь берем соответствующие файлы локализации: htpp://onix.opennet.ru/files/. Распаковываем дистрибутив и пакет локализации в любое удобное место, например в директорию /tmp. # tar zxvf nagios-1.1.tar.gz # tar zxvf nagios_rus_1_1.tar.gz
Копируем все необходимые файлы из пакета локализации в распакованный дистрибутив и затем, как обычно, проводим конфигурирование.
№12(13), декабрь 2003
# cp –R /tmp/nagios_rus_1_1/* /tmp/nagios-1.1/ # cd nagios-1.1 # ./configure --prefix=/usr/local/nagios ↵ --with-cgi-url=/nagios/cgi-bin --with-html-url=/nagios/ ↵ --with-nagios-user=nagios --with-nagios-grp=nagios ↵ --with-gd-lib=/usr/local/lib ↵ --with-gd-inc=/usr/local/include/gd
Я думаю, объяснять назначение ключей команды configure смысла нет. Поэтому сразу же переходим к компиляции. /usr/local/etc/nagios.sh stop
После того как этот процесс завершится успешно, останавливаем демона Nagios. Все-таки резать по живому не очень хорошо, и подобные действия могут вызвать разнообразные сбои в функционировании системы мониторинга. # make install
Вот теперь можно спокойно выполнять инсталляцию. # make all
В результате файлы из директории дистрибутива должны заменить те файлы, которые Nagios использовал до сегодняшнего дня. Таким образом, файлы из /tmp/ nagios-1.1/html должны попасть в /usr/local/nagios/share/, а скомпилированные файлы из /tmp/nagios-1.1/cgi в /usr/ local/nagios/sbin/. Снова запустив Nagios и обратившись к веб-интерфейсу, должны увидеть что-то вроде такой картинки:
49
администрирование Судя по всему, русификация прошла без сучка без задоринки. Следующая проблема, нуждающаяся в исправлении, – неработающая карта сети. При попытке воспользоваться пунктами «Карта сети» (statusmap.cgi) и «3D карта сети» (statuswrl.cgi) на экране вместо карты обычно появляется такое меню:
NOTE: After you install the necessary libraries on your system: 1. Make sure /etc/ld.so.conf has an entry for the directory in which the GD, PNG, and JPEG libraries are installed. 2. Run 'ldconfig' to update the run-time linker options. 3. Run 'make clean' in the Nagios distribution to clean out any old references to your previous compile. 4. Rerun the configure script. NOTE: If you can't get the configure script to recognize the GD libs on your system, get over it and move on to other things. The CGIs that use the GD libs are just a small part of the entire Nagios package. Get everything else working first and then revisit the problem. Make sure to check the nagios-users mailing list archives for possible solutions to GD library problems when you resume your troubleshooting. ********************************************************************
Ну а в случае, если вам повезло и вы нашли в указанном выше файле вот такое: checking for gdImagePng in -lgd (order 1)... yes GD library was found!
Причин этому может быть две. Первая – не работает библиотека GD, которую мы установили вместе с Nagios. И вторая – в используемом нами браузере отсутствует или неправильно работает подключаемый модуль для отображения vrml. Итак, начнем с первой проблемы. Если вы помните, перед компилированием Nagios мы использовали команду configure. Следует обратить особое внимание на параметры --with-gd-lib и --with-gd-inc, которые указывают на директории, где в нашей системе находятся заголовочные и библиотечные файлы пакета GD. Команда configure пытается автоматически подключить нужные файлы к проекту, но ей не всегда это удается. Обычно в процессе конфигурирования на экран выводятся соответствующие сообщения, но вся проблема в том, что туда же сыпется довольно много прочих диагностических сообщений, и поэтому найти и понять то, что нам нужно в этом винегрете, довольно сложно. Для более точного диагностирования проблемы очистим дистрибутив от файлов конфигурации, созданных во время предыдущей компиляции командой: # make clean
Затем перенаправим все сообщения команды configure в файл make.log c помощью следующей конструкции: # ./configure --prefix=/usr/local/nagios ↵ --with-cgi-url=/nagios/cgi-bin --with-html-url=/nagios/ ↵ --with-nagios-user=nagios --with-nagios-grp=nagios ↵ --with-gd-lib=/usr/local/lib ↵ --with-gd-inc=/usr/local/include/gd > make.log
Если во время компоновки gd не найден, то внутри файла make.log среди всего прочего будут вот такие надписи: checking for gdImagePng in -lgd (order 1)... no checking for gdImagePng in -lgd (order 2)... no checking for gdImagePng in -lgd (order 3)... no *** GD, PNG, and/or JPEG libraries could not be located... **** Boutell's GD library is required to compile the statusmap, trends and histogram CGIs. Get it from http://www.boutell.com/gd/, compile it, and use the --with-gd-lib and --with-gd-inc arguments to specify the locations of the GD library and include files. NOTE: In addition to the gd-devel library, you'll also need to make sure you have the png-devel and jpeg-devel libraries installed on your system.
50
значит с GD у вас все в порядке, и вы можете спокойно пойти попить кофе, пока я расскажу остальным, как избавиться от проблем с этой неуловимой библиотекой. По традиции начинаем с FreeBSD. Посмотреть, устанавливалась ли библиотека GD в эту систему стандартными средствами, то есть с помощью пакетов или портов, можно командой: # pkg_info | grep gd gd-1.8.4_6 A graphics library for fast image creation
Теперь мы знаем полное название пакета. Смотрим, куда установились его файлы. # pkg_-L gd-1.8.4_6 Information for gd-1.8.4_6: Files: /usr/local/bin/bdftogd /usr/local/bin/gd2copypal /usr/local/bin/gd2topng /usr/local/bin/gdparttopng /usr/local/bin/gdtopng /usr/local/bin/pngtogd /usr/local/bin/pngtogd2 /usr/local/bin/webpng /usr/local/include/gd/gd.h /usr/local/include/gd/gd_io.h /usr/local/include/gd/gdcache.h /usr/local/include/gd/gdfontg.h /usr/local/include/gd/gdfontl.h /usr/local/include/gd/gdfontmb.h /usr/local/include/gd/gdfonts.h /usr/local/include/gd/gdfontt.h /usr/local/lib/libgd.a /usr/local/lib/libgd.so /usr/local/lib/libgd.so.2 /usr/local/share/doc/gd/index.html
Итак, судя по выводу, параметры команды configure, относящиеся к библиотке GD, должны выглядеть так: --with-gd-lib=/usr/local/lib ↵ --with-gd-inc=/usr/local/include/gd
Давайте посмотрим, как можно добиться подобного эффекта для Linux-систем, основанных на rpm. В качестве примера возьмем ALT Linux. # rpm -qa | grep gd
администрирование libgd2-devel-2.0.4-alt2 gdm-2.4.4.5-alt1 gdk-pixbuf-loaders-0.22.0-alt2 gdk-pixbuf-0.22.0-alt2 libgd2-2.0.4-alt2 libgda2-1.0.0-alt1 gnome2-utils-gdict-applet-2.4.0-alt2 libgda2-devel-1.0.0-alt1
В отличие от FreeBSD, в Linux-системах библиотека GD обычно разделена на два отдельных пакета. Судя по всему, нас интересуют rpm-файлы libgd2 и libgd2-devel. Первый содержит динамически загружаемые библиотеки, ну а второй, соответственно, заголовочные файлы. # rpm -ql libgd2 /usr/lib/libgd.so.2 /usr/lib/libgd.so.2.0.4 # rpm -ql libgd2-devel /usr/include/gd.h /usr/include/gd_io.h /usr/include/gdcache.h /usr/include/gdfontg.h /usr/include/gdfontl.h /usr/include/gdfontmb.h /usr/include/gdfonts.h /usr/include/gdfontt.h /usr/lib/libgd.so /usr/share/doc/gd-2.0.4 /usr/share/doc/gd-2.0.4/index.html
Ну и наконец, универсальный способ, подходящий для любой Unix-подобной операционной системы. Им можно воспользоваться в случае, если все предыдущие попытки не дали никаких результатов. Нужно самостоятельно отыскать, где находятся файлы libgd.* и gd.h #find / -name libgd.* /usr/lib/libgd.so.1.2 /usr/lib/libgd.so.1 /usr/lib/libgd.so #find / -name gd.h /usr/include/gd.h
Теперь вы можете уверенно сказать, чему должны быть равны параметры --with-gd-lib и --with-gd-inc команды configure. Выполняем ее со всеми необходимыми настройками и, как описано выше, проверяем, найдена ли библиотека GD. И наконец, проводим компиляцию и инсталляцию, не забыв остановить демона Nagios. После этого карта сети (statusmap.cgi) должна приобрести вид, примерно похожий на этот:
№12(13), декабрь 2003
Теперь все те, кто ушли пить кофе, могут возвращаться. Сейчас мы начнем починку 3D-карты. Не работает она по причине того, что ваш браузер не знает, что делать с vrml-файлом, который возвращается в ответ на запросы к скрипту statuswrl.cgi. Для того чтобы все заработало как положено, нужно установить в используемый браузер модуль для работы с vrml или отдельную программу, предназначенную для тех же целей. Программного обеспечения, подходящего для этого, написано воз и маленькая тележка. Как обычно, пальма первенства по количеству экземпляров принадлежит Windows. Затем идет MAC OS и, наконец, бронзовое третье место занимает Linux. Итак, начнем с фаворита. При необходимости работать под управлением Windows и MAC-систем я предпочитаю использовать Cortona VRML Client по той простой причине, что он совместим с большинством наиболее распространенных браузеров, к числу которых несомненно относятся Internet Explorer, Netscape Navigator, Mozilla, iCab. Интересным фактом является то обстоятельство, что этот подключаемый модуль можно использовать даже из офисных приложений Microsoft PowerPoint, Microsoft Word. К сожалению, разработчики Cortona почему-то решили полностью проигнорировать Linux. Скачать дистрибутив можно с сайта http://www.parallelgraphics.com/products/ cortona/download/. Что делать после совершения этого сакраментального действа, мы обсудим немного позднее. Следующая достойная нашего внимания программа, называемая Cosmo player, живет по адресу: http://ca.com/ cosmo/html/. Работает в виде отдельного приложения и, конечно же, только под Windows и MAC. ExpressVR – конкурент Cortona для всем известной яблочной платформы. Под другими операционными системами не живет, попыток экспансии не предпринимает и, судя по последним тенденциям, скорее всего через некоторое время будет окончательно вытеснен своим многофункциональным противником. Предназначен только для Netscape Navigator и Internet Explorer. Скачать дистрибутив можно отсюда: http://members.aol.com/maxmac/vrml/download.html. FreeWRL – отдельное приложение, работающее в качестве самостоятельного vrml-браузера. Функционирует на платформах Linix и MAC и располагается по этому адресу: http://www.crc.ca/FreeWRL/. Следующий экземпляр в нашем списке называется VRwave и проживает тут: http://www.iicm.edu/vrwave. Предназначен для Linux и Windows. Замыкает стройные ряды vrmlклиентов OpenVrml, обитающий сугубо под Linux: http:// sourceforge.net/project/showfiles.php?group_id=7151 &release_id=192066. Кстати, стоит сделать маленькую ремарку по ходу изложения. Практически все программы, которые мы назвали предназначенными под Linux, теоретически должны работать и под другими Unix-подобными системами, в состав которых входит графический сервер X11. На самом деле программ, подходящих для наших целей, гораздо больше, чем вы могли бы подумать. Я постарался упомянуть лишь наиболее известные из них. Если же вы хотите непременно огласить весь список, то вам нужно провести поиск по слову vrml на следующих серверах, в народе ласково называемых софтомогильниками:
51
администрирование http://sourceforge.net http://freshmeat.net http://tucows.com http://filesearch.ru А здесь: http://www.chuvsu.ru/download/vrml/browsers/ можно найти очень неплохую подборку vrml-клиентов для Windows. Надеюсь, что среди подобного разнообразия вы сможете самостоятельно подобрать себе инструмент по вкусу. Теперь сделаем перерыв в изучении теории и попрактикуемся в том, как правильно провести инсталляцию и использование Cortona VRML Client в связке с браузером Microsoft Internet Explorer. Сделать это можно двумя способами. Начнем с самого простого. С помощью браузера идем по адресу: ht tp:// www.parallelgraphics.com/products/cortona/download/ и, выбрав нужный тип браузера, пользуемся кнопкой «online install».
Обратите внимание на пустой прямоугольник в центре страницы. Его появление означает, что в вашем браузере нет vrml-модуля. Нажимаем на кнопку «Install Now». После того как процесс скачивания закончится, перед нами появится следующее окно:
По окончании инсталляции текущая страница в браузере должна обновиться. И в центре нее появится вращающийся куб.
На этом первый способ инсталляции можно считать оконченным. Если в процессе выполнения этих инструкций что-то пошло не так, как должно было, и установка завершилась неудачно, то огорчаться не стоит. Можно выполнить все требуемые действия вручную. Итак, переходим ко второму способу инсталляции. Скачиваем дистрибутив, подходящий для нашего браузера. После запуска принимаем лицензионное соглашение и несколько раз жмем кнопку «Next». После распаковки файлов на экране должно появиться что-то вроде такой картинки:
Система может задуматься на минуту-другую, а затем снова очнется и начнет задавать вопросы.
Жмем «Yes» в знак того, что мы доверяем цифровой подписи ParallelGraphics LTD. Подобный механизм цифровых подписей для всех скачиваемых программ помогает избежать подмены или порчи дистрибутива во время его путешествия через сеть. На следующем экране выставляем во всех окошках галочки. Таким образом, мы назначаем vrml-клиента программой по умолчанию для обработки файлов wrl, wrml и wrz.
52
Требуется уточнить, каким образом мы будем отрисовывать vrml-сцены. Выбирайте один из пунктов в зависимости от программного обеспечения, установленного в вашей системе. Если вы ошибетесь, и у вас нет выбранного компонента, то ничего страшного не произойдет. Си-
администрирование стема самостоятельно переключит отрисовку в программный режим.
В открывшемся меню выберем пункт «Preferences». А затем, воспользовавшись вкладкой «Render», выбираем альтернативный механизм рендеринга. Лично я – человек ленивый, и не люблю читать readmeфайлы без нужды, поэтому на следующем экране отключаю такую возможность. А вот во втором окошке галочку лучше оставить нетронутой, потому что это позволит нам проверить, правильно ли работает vrml. Вслед за нажатием кнопки «Next» на экране появится 3D-сцена, изображающая постепенно расцветающую розу.
Думаю, вы сможете легко самостоятельно разобраться с настройками и изучить способы перемещения в трехмерном виртуальном пространстве. Теперь можно посмотреть на 3D-карту Nagios.
Если нам не удалось правильно угадать нужный режим отрисовки, то рядом откроется окно консоли с соответствующим сообщением.
Для того чтобы избавиться от этой надоедливой помехи, закрываем окно консоли и щелкаем правой клавишей мыши в середине окна с 3D-сценой.
№12(13), декабрь 2003
Выглядит она пока не так уж и красиво, но дайте время, и все еще изменится к лучшему. А теперь вновь одним прыжком вернемся к плоской карте сети statusmap.cgi. Для наглядности давайте представим, что наша система мониторинга наблюдает за сетью, изображенной на следующем рисунке:
53
администрирование У нас есть две отдельные подсети, созданные на основе управляемых коммутаторов 3com. Каждому из них выдан собственный IP-адрес. Таким образом, мы имеем возможность проверять их работоспособность с помощью подключаемого модуля check_ping. Внутренняя сеть включает в себя следующие компьютеры: Nagios – система мониторинга; Linux – рабочая станция на основе Linux; Win_2000 – рабочая станция на основе Windows 2000 Professional. Вторая сеть у нас используется как демилитаризованная зона. В нее включены серверы c именами WWW и Mail. Думаю, названия говорят сами за себя, и поэтому неудивительно, что на них запущены сервисы IMAP, POP3, SMTP и HTTP. Между собой сети соединены с помощью машины, фигурирующей под именем Inner_Firewall. Выход в Интернет защищает аппаратный межсетевой экран, называемый Outer_Firewall. В файле hosts.cfg содержатся следующие данные, полностью описывающие нашу сеть и ее хосты: define host{ name generic-host notifications_enabled 1 event_handler_enabled 1 flap_detection_enabled 1 process_perf_data 1 retain_status_information 1 retain_nonstatus_information 1 register 0 } define host{ use generic-host host_name Win_2000 alias Standard Windows Server address bianca parents 3com_Lan check_command check-host-alive max_check_attempts 10 notification_interval 120 notification_period 24x7 notification_options d,u,r } define host{ use generic-host host_name Linux alias Linux Server address lira parents 3com_Lan check_command check-host-alive max_check_attempts 10 notification_interval 120 notification_period 24x7 notification_options d,u,r } define host{ use generic-host host_name 3com_Lan alias 3COM inner Lan switch address 3com-lan check_command check-host-alive max_check_attempts 10 notification_interval 120 notification_period 24x7 notification_options d,u,r } define host{ use generic-host host_name Inner_Firewall alias Firewall PC parents 3com_Lan address inner-firewall
54
check_command check-host-alive max_check_attempts 10 notification_interval 120 notification_period 24x7 notification_options d,u,r } define host{ use generic-host host_name 3com_Dmz alias 3COM dmz switch address 3com-dmz parents Inner_Firewall check_command check-host-alive max_check_attempts 10 notification_interval 120 notification_period 24x7 notification_options d,u,r } define host{ use generic-host host_name Mail alias Mail Server address mailer parents 3com_Dmz check_command check-host-alive max_check_attempts 10 notification_interval 120 notification_period 24x7 notification_options d,u,r } define host{ use generic-host host_name WWW alias WWW Server address web parents 3com_Dmz check_command check-host-alive max_check_attempts 10 notification_interval 120 notification_period 24x7 notification_options d,u,r } define host{ use generic-host host_name Outer_Firewall alias Hardware Firewall address outer-firewall parents 3com_Dmz check_command check-host-alive max_check_attempts 10 notification_interval 120 notification_period 24x7 notification_options d,u,r }
Я думаю, что цитировать файл services.cfg с описанием сервисов нужды нет, потому что в нем нет ничего интересного, да и для повествования он некритичен, кроме того, каждый из вас может заполнить его нужными сведениями за пять минут. Если же у кого-то из читателей это действо вызывает затруднение, то тогда им прямая дорога в первую статью о Nagios. Прочитать ее можно в [1] либо на моем сайте: http://www.onix.opennet.ru. К сожалению, Nagios пока не умеет строить карту сети, более или менее приближенную к реальному расположению наблюдаемых объектов внутри нее. Несмотря на то что у нас есть две подсети на карте, все машины отображаются так, как будто они находятся в одном и том же сетевом облаке, то есть все свалено в одну кучу. С одной стороны, это упрощает процедуру рисования карты, но с другой – усложняет жизнь администратора. Представьте себе ситуацию, когда из строя выходит машина Inner_Firewall. При следующем цикле выполнения проверок нас засыпет лавина уведомлений о кри-
администрирование тическом состоянии хостов Inner_Firewall, WWW, Mail, 3com_Dmz и Outer_Firewall. Хотя на самом деле не работает только первый из всех вышеперечисленных компьютеров. Получается, что администратор должен самостоятельно догадаться, что привело к таким массовым сбоям. Для того чтобы впредь избежать подобных неприятностей, нам необходимо объяснить Nagios, как построена наша сеть и каким образом добираться до ее самых удаленных уголков. Делается это с помощью создания отношений «родитель» – «потомок» между всеми нашими хостами. После таких изменений критические уведомления будут приходить только для компьютера Inner_Firewall, все остальные машины, задействованные в данной проблеме, получат статус «недоступно». Согласитесь, это всетаки более соответствует действительному положению вещей в контролируемых сетях. Прародителем всех компьютеров считается машина, на которой работает процесс системы мониторинга. И уже от него строится цепочка.
ный факт, что фирменная документация в разделе «Determining Status and Reachability of Network Hosts» этот тег почему-то называет parent_hosts. Хотя если покопаться в исходных текстах Nagios, то понимаем, что на самом деле должен быть просто parents. Если в описании хостов неукоснительно придерживаться указания использовать тег parent_host, то при попытке сделать nagios reload для того, чтобы применить изменения в конфигурации, получим вот такие ошибки: Running configuration check... Nagios 1.1 Copyright (c) 1999-2003 Ethan Galstad (nagios@nagios.org) Last Modified: 06-02-2003 License: GPL Reading configuration data... Error: Could not add object property in file '/usr/local/nagios/etc/hosts.cfg' on line 74. ***> One or more problems was encountered while processing the config files... Check your configuration file(s) to ensure that they contain valid directives and data defintions. If you are upgrading from a previous version of Nagios, you should be aware that some variables/definitions may have been removed or modified in this version. Make sure to read the HTML documentation on the main and host config files, as well as the 'Whats New' section to find out what has changed. failed - aborting reload.
Ошибка будет именно на той строке, где впервые появляется тег parent_host. Думаю, других доказательств не нужно. Машины, считающиеся локальными по отношению к Nagios, находятся на одну ступеньку ниже в иерархии, и поэтому не должны использовать тег parents в своем описании. Все остальные машины, относящиеся к группе удаленных, в вышеуказанном теге пишут имя ближайшего родителя. Таким образом, для хостов Inner_Firewall, Linux и Win_2000 родителем является 3com_Lan. В свою очередь, Inner_Firewall указан родителем для 3com_Dmz. А 3com_Dmz выполняет ту же роль для хостов WWW, Outer_Firewall, Mail. Итак, разобравшись с понятием иерархии, посмотрим, как оно влияет на отображение наших сетей на карте.
Для правильной диагностики неполадок иерархия должна выглядеть так, как изображено на предыдущей схеме. С точки зрения Nagios бывают два вида хостов – «локальные» и «удаленные». Локальными считаются те, кто находится в том же сетевом сегменте, что и система мониторинга. Между ними не должно быть ни маршрутизаторов, ни межсетевых экранов. Если бы у нас были неуправляемые коммутаторы, не поддающиеся мониторингу, то локальными хостами считались бы Linux и Win_2000. Но в связи с тем, что между ними есть промежуточное звено в виде коммутатора 3com_Lan, который можно подвергнуть мониторингу, они переходят в разряд удаленных. А единственным локальным становится 3com_Lan. Добиться этого можно применением тега parents в определении хостов. Стоит обратить внимание на тот стран-
№12(13), декабрь 2003
55
администрирование ших сетей. Тут нам на помощь приходят два новых файла. Первый из них, hostextinfo.cfg, отвечает за добавочные атрибуты хостов, а второй, serviceextinfo.cfg, выполняет ту же функцию для сервисов. Кстати, не забудьте скачать отсюда: http://nagios.org/ download/extras.html файлы с коллекциями иконок, обычно называемые image packs. Итак, начнем с файла hostextinfo.cfg. define hostextinfo{ # Òåã, ñ êîòîðîãî äîëæíî íà÷èíàòüñÿ îïèñàíèå õîñòà host_name 3com_Lan # Èìÿ õîñòà, ê êîòîðîìó îòíîñèòñÿ îïèñàíèå icon_image 3Com.png # Èìÿ ôàéëà èêîíêè, êîòîðàÿ áóäåò îòîáðàæàòüñÿ ðÿäîì ñ èìåíåì # õîñòà. Èêîíêà ìîæåò áûòü â ôîðìàòå GIF, PNG èëè JPG. Ìîæåò # ñîäåðæàòü âíóòðè ñåáÿ ïðîçðà÷íûå îáëàñòè. Æåëàòåëüíî, # ÷òîáû èêîíêè áûëè ðàçìåðîì 40x40 ïèêñåëåé. Ðàñïîëàãàòüñÿ # îíè äîëæíû â äèðåêòîðèè logos. Îáû÷íî ýòà äèðåêòîðèÿ # íàõîäèòñÿ â /usr/local/nagios/share/images/logos icon_image_alt 3Com LAN Switch # Íàäïèñü, îòîáðàæàåìàÿ, åñëè âåá-ñåðâåðó íå óäàåòñÿ # çàãðóçèòü èêîíêó vrml_image 3Com.png # Èìÿ ôàéëà, êîòîðûé áóäåò èñïîëüçîâàòüñÿ êàê òåêñòóðà äëÿ êóáà, # èçîáðàæàþùåãî õîñò íà òðåõìåðíîé êàðòå. Ìîæåò áûòü â ôîðìàòå # PNG, JPG, GIF. Êàðòèíêà íå äîëæíà ñîäåðæàòü ïðîçðà÷íûõ # îáëàñòåé, èíà÷å ýòî áóäåò âûãëÿäåòü î÷åíü ñòðàííî. Äîëæíà # õðàíèòüñÿ â òîé æå äèðåêòîðèè, ÷òî è èêîíêà, îïèñàííàÿ # òåãîì icon_image statusmap_image 3Com.gd2 # Èìÿ ôàéëà, ãäå õðàíèòñÿ èçîáðàæåíèå, êîòîðîå áóäåò # èñïîëüçîâàòüñÿ êàê èêîíêà õîñòà íà ïëîñêîé ñåòåâîé êàðòå. # Ìîæåò áûòü â ôîðìàòå PNG, JPG, GIF, íî âñå-òàêè ëó÷øå, # åñëè äëÿ ýòîãî ôàéëà áóäåò èñïîëüçîâàòüñÿ ôîðìàò GD2, ïîòîìó # ÷òî äëÿ êàæäîãî öèêëà ðèñîâàíèÿ êàðòû èêîíêà áóäåò ñíîâà # è ñíîâà ïðèâîäèòüñÿ ê âèäó, óäîáíîìó äëÿ áèáëèîòåêè GD. # À ýòî çíà÷èò, ÷òî ìû áóäåì çðÿ âûïîëíÿòü îäíè è òå æå # áåñïîëåçíûå âû÷èñëåíèÿ. Ìîæåò ñîäåðæàòü âíóòðè ñåáÿ # ïðîçðà÷íûå îáëàñòè. Æåëàòåëüíî ÷òîáû èêîíêè áûëè ðàçìåðîì # 40x40 ïèêñåëåé. Ðàñïîëàãàòüñÿ îíè äîëæíû â äèðåêòîðèè logos. # Îáû÷íî ýòà äèðåêòîðèÿ íàõîäèòñÿ â /usr/local/nagios/share/ # images/logos
Думаю, выглядит довольно впечатляюще. Какой из способов отображения карты будет использоваться по умолчанию, указывает параметр default_statusmap_layout. Для трехмерной карты такой параметр называется соответственно default_statuswrl_layout. Оба этих параметра скрываются внутри файла cgi.cfg. Кроме заметного с первого взгляда лоска, мы к тому же приобрели более точное диагностирование сетевых неполадок. Все это, конечно, хорошо, но душа требует чего-то более красивого. Также хотелось бы уметь самостоятельно указывать расположение тех или иных объектов на картах. Такая задача нам по плечу, и сейчас вы научитесь управлять важнейшими параметрами отрисовки сетевых карт. Для начала мы раздадим каждому хосту и сервису по красивой иконке, а затем расположим их так, чтобы они максимально совпадали с нашим рисунком, основываясь на котором мы описывали содержимое на-
56
2d_coords 160,99 # Äâóìåðíûå êîîðäèíàòû òî÷êè, â êîòîðîé áóäåò íàõîäèòüñÿ öåíòð # èêîíêè õîñòà íà ïëîñêîé êàðòå. Ìîãóò áûòü òîëüêî # ïîëîæèòåëüíûìè ÷èñëàìè. Ðèñîâàíèå êàðòû íà÷èíàåòñÿ èç òî÷êè # 0,0 êîòîðàÿ ÿâëÿåòñÿ âåðõíèì ëåâûì óãëîì êàðòû. Êîîðäèíàòû # ïåðå÷èñëÿþòñÿ â ñëåäóþùåì ïîðÿäêå x, y 3d_coords 20.0,32.0,6.0 # Êîîðäèíàòû öåíòðà êóáà, ñèìâîëèçèðóþùåãî õîñò â ïðîñòðàíñòâå # òðåõìåðíîé êàðòû. Ìîãóò áûòü êàê ïîëîæèòåëüíûìè, òàê è # îòðèöàòåëüíûìè ÷èñëàìè. Ðàçìåð îäíîé ñòîðîíû êóáà 0.5 åäèíèö. # Îòðèñîâêà êàðòû íà÷èíàåòñÿ öåíòðà òðåõìåðíîé êàðòû, êîòîðûé # íàõîäèòñÿ â òî÷êå ñ êîîðäèíàòàìè 0.0, 0.0, 0.0. # Êîîðäèíàòû ïåðå÷èñëÿþòñÿ â ñëåäóþùåì ïîðÿäêå x, y, z notes_url http://192.168.80.2/nagios/notes/3com_lan.txt # Ññûëêà íà àäðåñ, ïî êîòîðîìó ëåæèò ôàéë c äîïîëíèòåëüíûìè # ñâåäåíèÿìè î õîñòå. Ïðè ùåë÷êå íà ñïåöèàëüíûé çíà÷îê # â áðàóçåðå áóäåò îòêðûò ýòîò ôàéë. Ýòî ïîëåçíî äëÿ çàïèñè # ðàçëè÷íûõ ñâåäåíèé, êîòîðûå íå âîøëè â ñòàíäàðòíûé øàáëîí # îïèñàíèÿ õîñòà Nagios. Íàïðèìåð, òàì ìîæíî íàïèñàòü äàííûå, # îòâå÷àþùèå íà âîïðîñ, êòî èç àäìèíèñòðàòîðîâ îòâå÷àåò # çà óïðàâëåíèå ýòèì ñåðâåðîì, ê êîìó îáðàùàòüñÿ â ñëó÷àå ïðîáëåì. # Îáðàòèòå âíèìàíèå íà URL, èñïîëüçóåìûé äëÿ óêàçàíèÿ ïóòü # ê ôàéëó. Äëÿ òîãî ÷òîáû ôàéëû ñ çàïèñêàìè ìîæíî áûëî õðàíèòü # íà òîì æå õîñòå, ÷òî è Nagios, ÿ ñîçäàë äèðåêòîðèþ # /usr/local/nagios/share/notes, è ïîýòîìó ìû òåïåðü ìîæåì # ïîëó÷èòü ê íåé äîñòóï èìåííî ïî òàêîìó URL. } define hostextinfo{ host_name Win_2000 notes_url http://listios.lan.domain.ru/Win_2000.html # Êñòàòè, ñòîèò îòìåòèòü, ÷òî äîáàâî÷íûå çàïèñêè î õîñòàõ ìîãóò # õðàíèòü íå òîëüêî íà òîì æå õîñòå, ãäå ðàáîòàåò Nagios, íî è íà # ëþáîì äðóãîì. Ãëàâíîå, ÷òîáû òàì ðàáîòàë âåá-ñåðâåð è URL
администрирование # áûë ïðàâèëüíî ïðîïèñàí icon_image win40.png icon_image_alt Windows workstation vrml_image win40.png statusmap_image win40.gd2 2d_coords 163,195 3d_coords 15.0,38.0,6.0 } define hostextinfo{ host_name Linux notes_url http://10.10.5.7/hostinfo.pl?host=Linux1 #  êà÷åñòâå URL äëÿ õðàíåíèÿ äîáàâî÷íûõ çàïèñîê ìîæíî èñïîëüçîâàòü # äàæå CGI.  çàâèñèìîñòè îò äàííûõ, ïåðåäàííûõ â çàïðîñå, âû áóäåòå # ïîëó÷àòü ñâåäåíèÿ î òîì èëè èíîì õîñòå. icon_image_alt Linux Workstation vrml_image mandrake.gd2 statusmap_image mandrake.gd2 2d_coords 60,198 3d_coords 30.0,38.0,6.0 } define hostextinfo{ host_name Mail notes_url http://192.168.80.2/nagios/notes/mail.html icon_image MailServer.png icon_image_alt Mail Server vrml_image MailServer.png statusmap_image MailServer.gd2 2d_coords 520,183 3d_coords 20.0,44.0,6.0 } define hostextinfo{ host_name WWW notes_url http://192.168.80.2/nagios/notes/www_notes.html icon_image openbsd.png icon_image_alt WWW Server vrml_image openbsd.gd2 statusmap_image openbsd.gd2 2d_coords 439,186 3d_coords 20.0,54.0,6.0 } define hostextinfo{ host_name Inner_Firewall notes_url http://192.168.80.2/nagios/notes/ inner_fw_notes.html icon_image freebsd40.png icon_image_alt Inner Firewall vrml_image freebsd40.png statusmap_image freebsd40.gd2 2d_coords 326,96 3d_coords 17.0,55.0,6.0
host_name WWW # Èìÿ õîñòà, íà êîòîðîì ðàáîòàåò ñåðâèñ service_description HTTP # Èìÿ ñåðâèñà èç ôàéëà services.cfg notes_url http://192.168.80.2/nagios/notes/service_www.html # Óæå ìíîãîêðàòíî âèäåííûé íàìè URL äëÿ äîïîëíèòåëüíûõ çàïèñîê icon_image apache.png # Èìÿ ôàéëà èêîíêè, êîòîðàÿ áóäåò îòîáðàæàòüñÿ ðÿäîì ñ èìåíåì # ñåðâèñà. Èêîíêà ìîæåò áûòü â ôîðìàòå GIF, PNG èëè JPG. Ìîæåò # ñîäåðæàòü âíóòðè ñåáÿ ïðîçðà÷íûå îáëàñòè. Æåëàòåëüíî, ÷òîáû # èêîíêè áûëè ðàçìåðîì 40x40 ïèêñåëåé. Ðàñïîëàãàòüñÿ îíè äîëæíû # â äèðåêòîðèè logos. Îáû÷íî ýòà äèðåêòîðèÿ íàõîäèòñÿ â # /usr/local/nagios/share/images/logos icon_image_alt Web Service # Íàäïèñü, îòîáðàæàåìàÿ, åñëè âåá-ñåðâåðó íå óäàåòñÿ çàãðóçèòü # èêîíêó, ïðèâÿçàííóþ ê ñåðâèñó } define serviceextinfo{ host_name WWW service_description SMTP notes_url http://192.168.80.2/nagios/notes/service_www.html icon_image apache.png icon_image_alt Web Service } define serviceextinfo{ host_name Mail service_description SMTP notes_url http://192.168.80.2/nagios/notes/service_smtp.html icon_image smtp.png icon_image_alt Web Service } define serviceextinfo{ host_name Mail service_description POP3 notes_url http://192.168.80.2/nagios/notes/service_pop3.html icon_image pop3_imap.png icon_image_alt Web Service } define serviceextinfo{ host_name Mail service_description IMAP notes_url http://192.168.80.2/nagios/notes/service_imap.html icon_image pop3_imap.png icon_image_alt Web Service }
Для того чтобы Nagios увидел созданные нами файлы hostextinfo.cfg, serviceextinfo.cfg, нужно внести в файл cgi.cfg следующие директивы.
} define hostextinfo{ host_name Outer_Firewall notes_url http://192.168.80.2/nagios/notes/ outer_fw_notes.html icon_image firebox_small.png icon_image_alt Outer Firewall vrml_image firebox_small.png statusmap_image firebox_small.gd2 2d_coords 620,80 3d_coords 16.0,42.0,6.0 } define hostextinfo{ host_name 3com_Dmz notes_url http://192.168.80.2/nagios/notes/3com_dmz.html icon_image 3Com.png icon_image_alt 3Com DMZ LAN Switch vrml_image 3Com.png statusmap_image 3Com.gd2 2d_coords 480,73 3d_coords 14.0,56.0,6.0 }
Теперь пришло самое время обсудить содержимое файла serviceextinfo.cfg. Принципы построения обоих файлов довольно схожи. define serviceextinfo{
№12(13), декабрь 2003
xedtemplate_config_file=/usr/local/nagios/etc/hostextinfo.cfg xedtemplate_config_file=/usr/local/nagios/etc/serviceextinfo.cfg
Я думаю, вы сможете самостоятельно положить файлы иконок в директорию /usr/local/nagios/share/images/ logos/. Кстати, стоит обязательно убедиться, что все файлы, создаваемые вами, принадлежат пользователю, от имени которого работает Nagios, иначе вы будете очень долго недоумевать, почему никаких изменений в картах не видно, хотя все сделано так, как в этой статье. К таким файлам относятся hostextinfo.cfg serviceextinfo.cfg иконки, записки и прочая мелкая живность. Кстати, создавать самостоятельно файлы иконок в формате библиотеки GD довольно просто. Мы говорили об этих файлах во время обсуждения тега statusmap_image файла hostextinfo.cfg. Для этого нужно взять файлы иконки в формате png и преобразовать его в формат GD с помощью утилиты pngtogd2, поставлявшейся вместе с библиотекой GD. Желательно, чтобы создаваемый файл был сохранен без компрессии изображения. Это позволит увеличить скорость работы функций библиотеки GD, отвечающих за загрузку в память и рисование иконок внутри
57
администрирование интерфейса Nagios. Если данные внутри файла не сжаты, значит, не нужно тратить время на их распаковку. Учитывая малый размер наших картинок, сжатие не принесет никакой выгоды. Например, для конвертации файла www.png в www.gd2 нужно подать следующую команду:
с ними довольно хорошо. Полюбоваться на результат можно на следующей картинке.
$ /usr/local/bin/png2gd2 www.png www.gd2 4000 1
Я думаю, с первыми двумя параметрами все ясно. Третий указывает размер порции кодирования, и четвертый – наличие компрессии. После некоторого количества наблюдений замечено, что в качестве размера порции кодирования можно писать какое угодно число. Для исходных файлов малого размера, к которым относятся и наши иконки, этот параметр смысла не имеет. И не забудьте подать процессу nagios команду «reload», которая заставит его обновить конфигурацию. Во FreeBSD это обычно делается так: /usr/local/etc/rc.d/nagios.sh reload. Если есть желание, можно нарисовать свои собственные иконки и использовать их вместо стандартных. Я именно так поступил с сервисами HTTP, SMTP, POP3 и IMAP. Для HTTP использовалось перо, потерянное индейцем Apache, а для всех остальных изображение открытого и закрытого почтового конверта. И хотя картинки получились размером чуть более, чем 40x40 пикселей, Nagios работал
58
Теперь у каждого хоста и сервиса есть не только личная иконка, но и на страничке с подробной информацией о каждом из них возникло вот такое изображение.
Если нажать на него, то можно почитать дополнительные сведения из файла, который мы описали тегом notes_url. Координаты точек, в которых должны рисоваться иконки и объекты наших хостов на плоской и трехмерной картах сети, не будут использоваться Nagios до тех пор, пока мы не выставим вот таким образом значения тегов default_statusmap_layout и default_statuswrl_layout в файле cgi.cfg. default_statusmap_layout=0 default_statuswrl_layout=0
администрирование Если вы все сделали правильно, то плоская карта сети будет выглядеть вот так:
Впечатляет, не правда ли?
Трехмерная карта выглядит тоже довольно хорошо. И самое приятное в этом то, что в трехмерное пространство можно добавить, например, подробный макет здания, в котором эта сеть находится, и поставить сервера в нужных помещениях. Но об этом мы поговорим в другой статье. Ну а если вместо вожделенной карты на экране появилась следующая надпись: You have not supplied any host drawing coordinates, so you cannot use this layout method. Read the FAQs for more information on specifying drawing coordinates or select a different layout method.
Значит, вы что-то напутали с тегами координат отрисовки. Еще одной из полезных возможностей, которую мы сегодня изучим, будет умение добавлять в страницы, создаваемые Nagios, свои вставки и заголовки. Каждая страница может иметь два заголовка и две вставки. Обычно таким образом в текст страницы можно вставлять корпоративную символику, справочные телефоны и прочие сведения, относящиеся к выбранной странице. Все заголовки страниц и вставки делятся на глобальные и локальные. Глобальные действуют на все страницы cgi, а локальные только на те, для которых они были определены. Тексты, записанные в файлах заголовков и разрывов страниц, вставляются в начало и конец тега <BODY> </BODY>страницы, создаваемой cgi. Обычно текст страницы после обработки выглядит так: <BODY> ãëîáàëüíûé çàãîëîâîê ëîêàëüíûé çàãîëîâîê ïåðâîíà÷àëüíûé òåêñò ãëîáàëüíàÿ âñòàâêà ëîêàëüíàÿ âñòàâêà </BODY>
№12(13), декабрь 2003
Давайте посмотрим, что нужно сделать для того, чтобы это работало на примере файла status.cgi. В директории /usr/local/nagios/share/ssi нужно создать следующие файлы: common-footer.ssi – файл глобального заголовка common-header.ssi – файл глобальной вставки status-footer.ssi – файл локального заголовка status-header.ssi – файл локальной вставки Я думаю, все уже сообразили, что имя для файлов локального заголовка и локальной вставки образуется с помощью сращивания имени подопытного файла cgi с надписями -footer.ssi и -header.ssi. Нужно помнить, что содержимое всех вышеперечисленных файлов перед добавлением в целевой файл никак не обрабатывается, то есть создать динамические заголовки и вставки без безумных ухищрений не получится, потому что нет возможности использовать в качестве генератора данных cgi или что-либо другое. Получается, что включаемые файлы должны содержать в себе только чистый html. Давайте рассмотрим содержимое всех файлов, применявшихся в этом примере: Ôàéë common-footer.ssi <p> <center> <h2> Ïî âîïðîñàì òåõïîääåðæêè îáðàùàòüñÿ íà tigrisha@sysadmins.ru èëè <a href="http://onix.opennet.ru">http://onix.opennet.ru</a> </h2> </center> </p> Ôàéë common-header.ssi <p> <center> <img src="../images/onix.png" border="0" alt="Nagios"> </center> </p> Ôàéë status-footer.ssi <p> <center> <h2> Ðàçäåëèòåëü ñòðàíèöû status.cgi</h2> </center> </p> Ôàéë status-header.ssi <p> <center> <h2>Òåñòîâûé çàãîëîâîê status.cgi</h2> </center> </p>
Как вы могли убедиться, все это работает довольно просто. Еще одной вкусностью, которой я с вами поделюсь, будет способность привязывать проигрывание звуковых файлов к определенным событиям. Например, моя система мониторинга при умирании какого-либо сервиса начинает изображать жалобно мычащую корову. Такая возможность очень полезна для администраторов, которые не хотят постоянно смотреть на веб-интерфейс Nagios или ежеминутно проверять свой почтовый ящик на предмет уведомлений о проблемах. Нужно всего лишь открыть в браузере или прикрепить на Active Desktop одну из этих страниц tac.cgi, status.cgi. После этого можно минимизировать браузер и заниматься своими делами. Как только случится какое-либо интересующее нас событие, Nagios начнет воспроизводить звук, связанный с ним. Для осуществления наших желаний есть следующие теги:
59
администрирование host_unreachable_sound – хост недоступен; host_down_sound – хост не работает; service_critical_sound – сервис в критическом состоя-
легко: нужно просто войти в режим управления сервисом или хостом и подать команду подтверждения проблемы.
нии;
service_warning_sound – сервис в состоянии предупреждения;
service_unknown_sound – состояние сервиса неизвестно;
normal_sound – все работает отлично, нет никаких проблем. Опцию normal_sound практически никто не использует. Но на всякий случай я решил ее упомянуть. Для того чтобы звуковое оповещение заработало, нужно поместить файлы звуков в формате wav внутрь директории /usr/local/nagios/share/media/, как всегда, не забыть о правах пользователя и принадлежности файлов. А затем добавить следующие записи в файл cgi.cfg. host_unreachable_sound=hostunreachable.wav host_down_sound=host down.wav service_critical_sound=servicecritical.wav service_warning_sound=servicewarning.wav service_unknown_sound=service unknown.wav normal_sound=noproblem.wav
В случае если в процессе мониторинга будет обнаружено одновременно несколько проблем, Nagios начнет проигрывать звук для наиболее критичной из них. После десятка или двух повторений одного и того же звука вам, наверное, захочется отключить звук. Сделать это довольно
После подобной обработки записи в таблице сервисов или хостов примут вот такой вид:
Я думаю, на сегодня хватит грызть гранит науки, и пора дать мозгам отдохнуть. Позволю себе попрощаться с вами в эту радостную минуту.
Литература: 1. Бешков А. Установка Nagios. – //Журнал «Системный администратор» №2(3), февраль 2003 г. – 6-14 с. 2. Бешков А. Мониторинг Windows-серверов с помощью Nagios. Часть 1. – //Журнал «Системный администратор» №7(8), июль 2003 г. – 12-19 с. 3. Бешков А. Мониторинг Windows-серверов с помощью Nagios. Часть 2. – //Журнал «Системный администратор» №8(9), август 2003 г. – 12-23 с.
60
hardware
ВТОРАЯ ЖИЗНЬ МОДЕМОВ
ПАВЕЛ ЗАКЛЯКОВ 62
hardware Лирическое отступление Если на обычном, пользовательском компьютере у вас стоит два модема, то это, наверное, уже много, а вот если говорить о серверах, то модемов много не бывает. Простой пример: распределённая сеть узлов, единый центр. Узлы связываются с центром и/или центр с узлами. На центральный узел осуществляется DDoS-атака. Как в этом случае связываться и передавать данные? Хорошо, если это происходит в Москве или другом крупном городе, где пальцем ткни, попадёшь в какого-нибудь провайдера. Несколько тысяч долларов, и у вас будет несколько резервных каналов связи на такой случай. Усугубим проблему, а если узлы находятся в других городах? Вот и получается, что самое оптимальное и по цене, и по реализации решение, если нет необходимости в создании видеоконференций, – создание резервной модемной сети связи. По моему мнению, даже в простой маленькой сетке должен быть на сервере модем, например, на случай передачи срочной почты, если упадёт основной канал подключения к Интернету. Замечание: в недавние времена в столице, когда подключиться по выделенной линии было дорого, многие создавали домашние локальные сети, скидывались на один общий телефон и безлимитный dial-up-интернет. Получалось медленно, но всё же лучше, чем ничего, для почты и ICQ вполне хватало на несколько человек. Во многих корпоративных сетях, если пропускная способность подключения к Интернету мала и не предвидится её увеличения, многие пользователи на своих рабочих местах имеют модемы, предпочитая соединяться по dial-up, когда общий интернет-доступ совсем не работает [5, стр. 208-209]. Если в организации имеется централизованная политика безопасности, контролируются все подключения к Интернету, то такого быть не должно. Злоумышленники и так постоянно пытаются обойти средства защиты, а тут появляется удобная лазейка для них. Зачем пытаться взломать МЭ снаружи, когда можно с большой лёгкостью взломать внутреннего модемного пользователя, установить у него cниффер и получить пароли для доступа к МЭ. Конечно, есть пользователи, которые могут настроить свой персональный МЭ для модема не хуже общего, но согласитесь, что это скорее исключение. Случаев неконтролируемого применения модемов довольно много, многие из них описаны в литературе, в частности А.Лукацкий [5] пишет: «В процессе проведения аудита безопасности в одном из московских банков было обнаружено несколько компьютеров, к которым были подключены модемы. В процессе разбирательств выяснилось, что только на одном из компьютеров применение модема было «узаконено» (для доступа к обновлениям баз данных юридической консультационной системы). Другие модемы были установлены сотрудниками, которые использовали их для доступа в Интернет в обход МЭ локальной сети банка. В одном случае на компьютере с подключённым модемом была найдена программа pcAnywhere, которая позволяла сотруднику работать с конфиденциальными данными из собственного дома». Всё это говорит о том, что если системный администратор или администраторы не успевают за новыми и
№12(13), декабрь 2003
старыми техническими решениями, то за них это делают пользователи. В конкретном примере выше это «отставание» было в вопросах организации резервной сети связи, выделения более широкого канала доступа к Интернету и организации безопасного удалённого доступа. Нередко администраторы вообще не знают о том, что определённые виды трафика разумнее делать более приоритетными по сравнению с другими. (Например, с помощью битов поля TOS в заголовках IP-пакетов.) Чтобы такого не происходило и администратор был всегда «на высоте», рассмотрим несколько вопросов, связанных с использованием модемов.
Какие задачи можно решать с помощью модемов? 1. Можно организовать резервную сеть связи. Если у организации несколько филиалов в разных городах, то это вполне здравое решение. Оплатить межгород может оказаться дешевле, чем заказать иные виды резервной связи. Следует отметить, что если и имеется тенденция к замене АТС на более современные цифровые, то темпы замен заметно отстают от последних модемных решений. Это означает, что для связи с каким-нибудь сельским районом совсем не нужен самый последний протокол v.92. Что и говорить, если постоянно появляются небольшие заметки, как эти v.92 или v.90 отключить. Даже v.34 (28800) в условиях использования нескольких ретрансляторов междугородней связи может оказаться завышенным требованием. 2. Можно организовать резервную сигнальную сеть. Если денег нет на мобильные терминалы [6], нет денег на Интернет, либо деньги на Интернет есть, но ищется более надёжное решение (с меньшим числом используемых элементов), то возможна организация отправки пейджинговых сообщений с помощью тонального набора. 3. Можно использовать функцию «факс». Не секрет, что мы далеки от цивилизованной рекламы. Один раз разместив свой факсовый номер где-то в открытом источнике, справочнике или засветив его на какой-нибудь выставке, вы обрекаете его на постоянные факсовые рассылки отнюдь не по направлению вашей деятельности. Вопрос имеет глубокие юридические корни, однако, если бороться со следствием, то можно установить факс-модем и, настроив mgetty (или vgetty), научить его принимать факсы. 4. Можно использовать функцию «автоответчика» и сопутствующие ей. Голосовая почта и автоответчик могут зарегистрировать нужные звонки, проинформировать клиентов о часах работы вашей организации, рассказать о наличии ресурсов в сети Интернет. Даже при небольшом умении может прайс-лист по запросу зачитываться по телефону. Если во времена 286-х были отечественные программки вроде spp.exe (www.samag.ru/sourse/spp.zip) порядка 44 Kб, которые могли на PC Speaker читать понятно, без особой интонации, при этом различая обычную интонацию и вопросительную, то сейчас, я думаю, вообще не проблема научить компьютер читать текстовые файлы.
63
hardware * From : Anton Loginov, 2:5024/11.30@fidonet ============================================================================= Áûëà òàêàÿ ïðîãðàììà – spp.exe, êîòîðàÿ çàñòàâëÿëà êîìïüþòåð ïðîèçíåñòè ñïèêåðîì ôðàçó, çàäàííóþ â êîìàíäíîé ñòðîêå. Ïðè ýòîì îíà ðàçëè÷àëà îáû÷íóþ èíòîíàöèþ è âîïðîñèòåëüíóþ. Ïðîãðàììà áûëà ðóññêàÿ. Ñðåäè ïðî÷èõ áóêâ îíà çíàëà è ðàçíûå ñèìâîëû, íàïðèìåð íà $ ãîâîðèëà «äîëëàðû». Èòàê – íî÷ü, ëóíà, çà êîìïüþòåðîì ñèäèò óñòàëûé ñèñòåìíûé îïåðàòîð, è ðàçáèðàåò User's UpLoad íà ñâîåé BBS. Âèäèò – ïðîãðàììà spp.exe áåç êîììåíòàðèÿ. Õîòåë îí å¸ óæå F8, íî ëþáîïûòíî ñòàëî – ÷òî îíà äåëàåò? Ñîñòîÿëñÿ ñëåäóþùèé äèàëîã: Ñèñòåìíûé îïåðàòîð: spp.exe Êîìïüþòåð: "ïøø-ñññ..." – ëåãêîå øèïåíèå ñïèêåðà, òèïà õîòåë ãîâîðèòü, à íå÷åãî! Ñèñòåìíûé îïåðàòîð: spp.exe /? Êîìïüþòåð, ãîëîñîì ðîáîòà ñ ë¸ãêèì ãðóçèíñêèì àêöåíòîì: KÎÑÀß ÑKÎÁKÀ ? Ñèñòåìíîãî îïåðàòîðà ÷óòü óäàð íå õâàòèë – äóìàë ãëþêè ó íåãî íà÷àëèñü... Âîò êàê áûâàåò.
5. Можно сделать BBS (Bulletin Board System). Хотя последний раз я коннектился к BBS и провёл несколько ночных часов уже как лет 7 назад, не меньше, так что не знаю, актуальны они ещё или нет. 6. Можно сделать почтовый (UUCP) сервер. До сих пор есть провайдеры, которые помимо обычного набора протоколов для организации доступа и работы с почтой tcp/ip/ppp + pop3/imap/smtp позволяют почту забирать по UUCP. А в школе, где я учился, и по сегодняшний день висит UUCPпочта для внутреннего обмена сообщениями, поднятая моим бывшим одноклассником на базе Red Hat Linux v.5.2. Uptime-системы уже исчисляется тысячами дней. Замечание: имеется неплохой клиент для приёма и редактирования сообщений для DOS. Так что, имея загрузочную дискету, 286, хоть с монохромным CGA-монитором, и модем можно быть равноправным участником почтового обмена и по сей день! 7. Можно сделать ФИДО-шный почтовый сервер (node). Для этого, правда, если не изменились порядки, для начала придётся побыть обычным пользователем ФИДО (point) порядка полгода. 8. Можно поднять dial-in-сервер, скажем, для доступа в Интернет. 9. Можно сделать шлюз IP-телефонии при наличии достаточных функций у модема, хотя, честно признаюсь, ни у кого такого не видел, и скорее эта возможность теоретическая. 10. Можно объединить частично или полностью вышеупомянутые возможности.
Какой модем купить? По поводу подключения нескольких модемов и модемных пулов мы поговорим ниже. А пока заметим, что не все пункты реализуемы всеми модемами, поэтому для решения той или иной задачи лучше остановить выбор на лучших моделях. Каждый волен выбирать, что ему больше нравится и больше подходит по цене. Я свой выбор остановил на старых профессиональных модемах фирмы ZyXEL серии 1496. Что ни говори, а стоечные версии и модемные пулы дороги, посему лучше выбирать профессиональные модели ближе к пользовательскому классу. На мой взгляд, таковыми являются три модели: ZyXEL U-1496B+, U-1496E+, U-1496S+, либо без «+».
64
Ðèñóíîê 1. Âíåøíèé âèä ìîäåìîâ: a) U-1496B+ á) U-1496E+ â) U-1496S+(U-1496+)
Именно доступность на рынке (цены порядка $7-20), высокое качество и широкий набор услуг обусловили мой выбор. Конечно, можно было взять и другие модели. Но тут критерий выбора был таков: если модемы ZyXEL, в частности U-1496S+ и USR Courier используются в банкоматах, то на них и стоит ставить свой выбор по надёжности. Касаемо хорошо работающих Courier, так они дороги, и я встречал глючные Courier, купленные дороже чем $150, может, это было исключение, но реализация того же ZyXEL под шину ISA (с определителем и голосовыми функциями) обойдётся куда дешевле ($7-10). Конечно, шина ISA сейчас не везде есть, но зато те, у кого она есть, могут в полной мере получить от неё пользу. За $100 можно собрать неплохо работающий сервер с не одним модемом на базе какого-нибудь Pentium. Перед тем как разобрать модемы и начать их улучшать, хотелось бы сделать небольшой ликбез в области постоянной памяти, так как мы столкнёмся непосредственно с ней. Те, кто знакомы с устройством и видами постоянной памяти, могут смело пропустить этот раздел.
hardware Организация постоянной памяти ПЗУ ПЗУ – постоянное запоминающее устройство, оно же ROM, Read Only Memory. Рассмотрим на пальцах работу данной схемы. В первом приближении для организации такой памяти ничего сложного не надо – простые перемычки, и устройство готово.
Ðèñóíîê 2. Âíóòðåííåå óñòðîéñòâî îäíîé ÿ÷åéêè ïàìÿòè íà 8 áèò. Çàïèñàííîå ÷èñëî (01101011)
При подаче напряжения на вход, например, логической «1», на выходах, соединённых с входом, появится тоже «1». На неподключенных выходах (болтающихся в воздухе) будет «0». Если надо запомнить два байта, берём два таких устройства, если нужно запомнить n2 байт, берём n2 таких устройств. Легко заметить, что подобная линейная организация неудобна и избыточна, поэтому на практике используется двухмерная реализация, когда для снятия данных используются одни и те же выводы. Потеря пропускной способности (нельзя параллельно считывать все ячейки) компенсируется значительным упрощением схемы. Для того чтобы сигналы с разных ячеек не мешали друг другу, используются диоды.
Ðèñóíîê 3. Âíóòðåííåå óñòðîéñòâî 2-õ ÿ÷ååê ïàìÿòè (4 + 4 áèòà), çàïèñàíî: 1101 è 0101 à) íåóäîáíûé ñïîñîá èçîáðàæåíèÿ á) óäîáíûé ñïîñîá èçîáðàæåíèÿ
№12(13), декабрь 2003
Использовать 1024 вывода для выбора нужной ячейки также неразумно. На практике для выбора нужной ячейки используется несложный декодер, встроенный в то же ПЗУ, преобразующий двоичный параллельный сигнал в выбор нужной линии (ячейки) ПЗУ. Дорисовав последовательно с каждым диодом плавкие предохранители, целые, если диод есть, и сгоревшие предохранители вместе с диодами, если их в схеме нет, мы получим схему, более-менее приближающуюся к реальности и встречающуюся в литературе. На практике организация записи в ПЗУ организуется по-разному. Если тираж очень большой, то дешевле получается штамповать уже зашитые ПЗУ, как обычные алюминиевые CD. Если тираж меньше и заранее неизвестно, что будет прошито, то дешевле обходится производить матрицы с диодами и предохранителями, после чего прожигать предохранители у ненужных ячеек либо на заводеизготовителе, либо продавать непрошитые микросхемы. В данные микросхемы возможно осуществить одноразовую запись. Что-то вроде обычного CD-R получается, правда, аналога мультисессионности тут пока не придумали. По аналогии с пишущими приводами для записи CD существуют программаторы, осуществляющие запись. Если на диоды, используемые при выборе какой-то ячейки памяти, посмотреть внимательно, то можно заметить, что у всех у них используется общий анод (или катод, если модифицировать схему). То же самое можно сказать про любую ячейку, у диодов, ответственных за её выбор, имеются общие выводы. Если взять половину транзистора, не обращая внимания на всё остальное, то это по сути тот же самый p-n переход. На практике, при реализации схемы в интегральном исполнении, оказывается более выгодным вместо отдельных групп диодов создавать n-p-n транзисторы с несколькими эмиттерами. Поэтому нередко ту же самую электрическую схему организации ПЗУ можно увидеть с транзисторами в следующем виде.
Ðèñóíîê 4. Ñõåìà ÏÏÇÓ ïîñòðîåííàÿ: a) íà äèîäàõ á) íà ìíîãîýìèòòåðíûõ òðàíçèñòîðàõ
65
hardware При занесении информации через диоды или эмиттеры шин с информационными нулями пропускаются большие токи, выжигающие плавкие перемычки. При подаче адресного импульса сигналы появляются только на тех выводах, где перемычки сохранены. Так как прошивка данного вида ПЗУ возможна один раз в жизни, то в зарубежной литературе данный вид ПЗУ помимо ROM имеет ещё одно название OTP ROM (One-Time Programmable ROM), иногда One-Time опускают и получается ещё одно более общее название PROM (Programmable ROM). В случае, если необходимо иметь возможность редкой перепрошивки записанных данных, следует использовать ППЗУ. Замечание: современные ПЗУ могут иметь немного отличную и своеобразную организацию, будучи построенными на полевых транзисторах либо смешанным образом. В этом случае единичный элемент может выглядеть и так.
Ðèñóíîê 5. Îäèí èç âàðèàíòîâ îðãàíèçàöèè ýëåìåíòà ïàìÿòè ñ ïîìîùüþ ïîëåâîãî òðàíçèñòîðà
ППЗУ ППЗУ – перепрограммируемое ПЗУ, ППЗУ с УФ-стиранием, EPROM (Erasable, Programmable, Read-Only Memory), UV-EPROM (UltraViolet EPROM). Несколько более дорогая технология, чем одноразовые ПЗУ, имеющая некоторые преимущества. В случае выполнения определённых действий позволяющая стирать старые и записывать новые данные. По внутреннему устройству данная память отличается от обычных ПЗУ. Вместо диодов и многоэмиттерных транзисторов используются специальные полевые МДП (металл-диэлектрик-проводник)-транзисторы, в частности МОП (металл-оксид кремния(окисел)-проводник) c плавающим затвором.
этот затвор не будет помещён заряд. Для этого между истоком и стоком прикладывается напряжение около 30 В, при этом происходит лавинный пробой, на затворе образуется остаточный заряд достаточный для образования канала под затвором. Положительный заряд на затворе притягивает свободные электроны из подложки, а притянутые электроны создают канал, способный проводить электрический ток. Транзистор становится проводящей цепью. Если заряды на плавающем затворе не накоплены, то данный транзистор ток не проводит. Таким образом можно различать логические «1» и «0». Для стирания данных с ПЗУ необходимо удалить накопленный на плавающем затворе заряд. Для этого используют ультрафиолетовое излучение. Микросхемы данного вида памяти имеют прозрачные окошечки, выполненные из кварцевого стекла. Обычно они заклеены чем-то непрозрачным. (Данные микросхемы мы встретим далее в модемах ZyXEL.) Ультрафиолетовое излучение за счёт попадания на кристалл и его ионизации позволяет постепенно растечься накопленному заряду. В зависимости от интенсивности УФ-излучения процесс стирания может колебаться от 10 минут и выше. Несмотря на то что для стирания рекомендуется использовать освещённость порядка 100 Вт/ м2 при времени экспозиции 1 час, редко кто оказывается в состоянии ждать такое количество времени. Срок хранения информации в ПЛМОП ППЗУ практически бесконечен – постоянная времени утечки заряда составляет десятки лет. У данной технологии также есть и минусы: малое число возможных циклов перепрограммирования, примерно порядка 10, плюс для стирания необходимо наличие источника УФ-излучения и другие связанные с этим неудобства. Так как у ПЛМОП-транзисторов нет затвора, то для выбора одного элемента памяти, как один из вариантов, последовательно с ними включаются обычные полевые транзисторы, что, несомненно, усложняет схему. Следующая технология лишена этих недостатков.
ЭС ППЗУ Электрически стираемые ППЗУ, EEPROM, E2PROM (Electrically Erasable PROM), как легко предположить из названия, вместо ультрафиолетового излучения для стирания используется электрический ток. В районе 1967 года для решения вышеописанных неудобств с УФ ППЗУ, в частности, невозможности электрического стирания, были придуманы новые решения. В качестве ячейки памяти было предложено использовать транзисторы, выполненные по новой на то время МНОП (металл – нитрид кремния – оксид кремния(окисел) – полупроводник) или МАОП (металл – алунд – оксид кремния – полупроводник)-технологии.
Ðèñóíîê 6. Ïîëåâîé òðàíçèñòîð ñ ïëàâàþùèì çàòâîðîì (ÏËÌÎÏ)
Из рисунка легко понять, почему затвор, состоящий из поликристаллического кремния, называется плавающим. Он со всех сторон окружён двуокисью кремния, не имеет выводов и соединений с остальной схемой. Такой транзистор представляет собой разомкнутую цепь до тех пор, пока на
66
Ðèñóíîê 7. Òðàíçèñòîð, âûïîëíåííûé ïî ÌÍÎÏ-òåõíîëîãèè
hardware Транзистор, выполненный по МНОП-технологии, представляет из себя обычный МДП-транзистор, в котором диэлектрик состоит из двух слоёв. Поверх обычного диоксида кремния, используемого в МОП-транзисторах, нанесён ещё слой нитрида кремния. Нитрид кремния обладает очень высоким сопротивлением, значительно большим, чем диоксид кремния. Эффект памяти в МНОП-транзисторах основан на изменении порогового напряжения транзистора при наличии захваченного в подзатворном диэлектрике положительного или отрицательного заряда, который хранится на глубоких (1.3-1.5 эВ) ловушках, в нитриде кремния вблизи границы SiO2-Si3N4 [11]. (В транзисторах памяти фирмы Hitachi толщина слоя окисла составляет порядка 20 ангстремов, а нитрида кремния – порядка 300-500 ангстремов [12].) Если на затвор подать напряжение порядка 30 В относительно подложки, то в течение 5 мс между тонким слоем окиси кремния и слоем нитрида кремния под затвором за счёт туннельного эффекта появятся неподвижные заряды. На образование токопроводящего канала между истоком и стоком будет влиять суперпозиция двух полей, от затвора и от накопленных в ловушках зарядах. Этим и объясняется следующая ВАХ МНОП-транзистора.
Ðèñóíîê 8. ÂÀÕ (âîëüò-àìïåðíàÿ õàðàêòåðèñòèêà) ÌÍÎÏ-òðàíçèñòîðà
Разность пороговых напряжений транзистора в ВАХ и фиксирует запись логических «0» или «1» в ЭС ППЗУ. Для того чтобы снять накопленные заряды (стереть записанную информацию), необходимо на затвор подать напряжение порядка 30 В обратной полярности. В МНОП количество циклов перезаписи очень велико, однако обращения для чтения после записи постепенно уменьшают заряды, поэтому длительность сигналов чтения лимитирована. Как правило, ЭС ППЗУ допускает 1011-1012 обращений, пока заряд начинает заметно снижаться. В некоторых ЭС ППЗУ этого типа вместо нитрида кремния используется аналогичный по свойствам оксид алюминия (алунд), при этом технология называется МАОП и получаются не p-канальные, а n-канальные приборы, причём нормально открытые. При записи их пороговое напряжение не снижается, а повышается. Большим преимуществом МАОП и МНОП ЭС ППЗУ является наличие у запоминающих транзисторов внешнего управляющего затвора, с помощью которого и производится выборка ячейки.
Flash-память То, что у каждой ячейки ЭС ППЗУ имеется возможность записи и удаления одного бита за одну операцию, это хорошо, но реально на практике это порождает много проблем и замедляет процесс перезаписи. Если ёмкость ПЗУ
№12(13), декабрь 2003
составляет 128 Кб, то это означает, что следует выполнить порядка одного миллиона стираний. Следует отметить, что это не самый большой размер встречающейся на сегодня памяти. Для упрощения процесса стирания, чтобы это можно было сделать одной или несколькими командами, схема ЭС ППЗУ была немного внутренне усложнена и появилась на свет так называемая flashEEPROM-память или flash-память. В технологии непосредственного хранения и записи информации во flash-памяти ничего нового не появилось. Сейчас это наиболее ходовая и удобная память, используемая в компьютерной и бытовой технике. Технология выпуска flash-памяти несколько дороже всех предыдущих, но получаемые преимущества с лихвой окупают повышение затрат. Замечание 1: в некоторой литературе flash-EEPROM переводится как мигающий-EEPROM, моё мнение, что это не совсем правильно, если дословно перевести слово flash, то получится вспышка. Скорее всего, этот смысл и закладывали разработчики данной технологии, насколько быстра вспышка, настолько быстро и осуществляется стирание данных из памяти. Помимо этого, если посмотреть на технологию стирания УФ ППЗУ, о которой написано чуть выше, то именно вспышка как раз лучше всего подходит по смыслу. Замечание 2: в иностранной литературе наблюдается некоторая путаница, так, у них имеется ещё одно сокращение для обозначения ЭС ППЗУ, а именно EAROM (Electrically Alterable ROM). По сути ничего нового не придумано, однако имеются два различных способа обозначений, частично противоречащих друг другу: часто схемы запоминающих устройств с более высокой ёмкостью обозначают как EEPROM, а с меньшей как EAPROM. Также через EEPROM иногда обозначают схемы запоминающих устройств, которые стираются целиком или поблочно, как flash-память, а под EAPROM понимают запоминаемые устройства, стираемые только по битам, либо по байтам. В плане внесения путаницы в обозначения мы также не стоим на последнем месте, иногда под ПЗУ у нас понимается любое ПЗУ из вышеописанных, в том числе и flash-память. Все описанные выше типы памяти имеют одинаковое обозначение на электрических схемах, за исключением случаев, если используется функция записи. Выпуск памяти как отечественными, так и импортными производителями, производится в вариантах, сопрягаемых с ТТЛ, nМОП и КМПОП-схемами. Это означает, что в пределах одной логики микросхемы памяти взаимозаменяемы. Сделано это целенамеренно с целью удешевления производства на этапах перехода к более массовому выпуску. Факт, что микросхемы памяти можно менять, нам пригодится при перепрошивке модемов ZyXEL в следующем разделе.
Перепрошивка модемов, использующих ПЗУ Итак, после того как у меня появились вышеописанные модемы ZyXEL и возникла идея подключить их к Linuxсерверу, я подумал, что неплохо было бы поменять в них прошивку на более современную перед установкой, благо, что такое ПЗУ я себе представлял довольно чётко. Для этого два внешних модема пришлось разобрать.
67
hardware
Ðèñóíîê 10. Âíóòðåííèé âèä ìîäåìîâ, ÷àñòü, ãäå íàõîäèòñÿ ÏÇÓ. a) U-1496B+ á) U-1496E+ â) U-1496S+
Ðèñóíîê 9. Ðàçáîð ìîäåìîâ. Âèä ñíèçó: a) U-1496B+ á) U-1496S+
Во всех трёх встретились две микросхемы ПЗУ с версиями. Это были ППЗУ с УФ-стиранием.
Именно заменой их мы и займёмся сейчас. Счастлив тот, у кого есть программатор, кварцевая лампа и два настроенных устройства /dev/hands и /dev/head. Менее часа, и проблема смены версии более не существует. К сожалению, первого устройства у меня под руками не оказалось, да и взять ненадолго не у кого тоже было, посему я пошёл по пути, описанному ниже. Преамбула: несколько лет назад один из моих знакомых, перепрошивая модем Acorp-56EMS на своём компьютере, имел возможность на практике подтвердить один из законов Мерфи: «Если какая-то неприятность может случиться, то она случается». Как назло во время перепрошивки на время пропало электричество. Модем умер, он отказывался вообще себя как-либо идентифицировать, мигать лампочками и подавать какие-либо признаки жизни. После был куплен новый модем, а сломанный долго валялся у знакомого в ящике, после чего был подарен мне как «радиогубителю со стажем» в надежде, что мне он принесёт большую пользу, чем если бы он продолжал пылиться. Расчёт оказался как никогда точен. Модем переехал ко мне. Где-то через пару месяцев, в очередной раз, когда у меня появился блеск в глазах и желание чего-то покрутить, я взял отвёртку и разобрал модем. См. рисунок 11.
Ðèñóíîê 11. Ðàçîáðàííûé ìîäåì Acorp-56EMS
68
hardware Схема модема оказалась самой обычной, ПЗУ (flash), как полагается, стояла на панельке. Преамбула к преамбуле: незадолго до этого я на своём Pentium-100 на Asus P/I-P55TP4N как раз занимался тем, что перепрошивал себе BIOS с целью: замены логотипа на более приятный моему глазу и отвоёвывания у жадного компьютера разницы между 9.1 Гб и 8.4 Гб, так как мой новый винт не хотел видеться в полном объёме. Мой школьный друг, зашедший ко мне тогда в гости, вдохновился тем, какие неизведанные возможности может сулить обновление версии BIOS (перед этим я с полгода жил, не используя свой диск в полном объёме по причине обычной нехватки времени) и решил повторить у себя операцию с обновлением и перепрошивкой BIOS. Пытаясь залить более совершенный BIOS от Pentium-II объёмом 256 Кб в ПЗУ объёмом 128 Кб на материнской плате первого Pentium, знакомый не знал тогда, что его ждёт неудача и поход ко мне с ПЗУ и винтом, так как на последний, а не на дискету была сохранена старая прошивка перед записью новой. Что делать, не пропадать же другу? Была выполнена известная операция перепрошивки «на лету», из работающего компьютера я вытащил свою ПЗУ, вставил его и зашил обратно ему его версию. Всё прошло на ура. Припоминая свой недавний успех, я, недолго думая, решил вытащить flash из модема с целью её изучения и возможной прошивки в материнской плате. Но как выяснилось позже, это и не понадобилось, включив ради интереса модем без микросхемы памяти, оказалось, что он жив! Загорелись лампочки и на команду «AT» модем бодро отвечал «ok», правда, ничего более, кроме как «AT», он не понимал. На включённом модеме я воткнул ПЗУ обратно, модем продолжил жить своей жизнью. После этого я подключился к Интернету (хорошо, когда есть несколько модемов в компьютере) и нашёл там много информации по перепрошивке модемов Acorp и саму прошивку. Нам понадобится только одна ссылка – [13]. В процессе перепрошивки модему безразлично, что вы на нём прошиваете, то ли его родную прошивку, то ли что-то другое, главное, чтобы прошиваемая микросхема поддерживалась модемом, проверки содержимого прошиваемой программы нет. Соответственно, я решил компенсировать отсутствие программатора тем, что у меня есть «волшебный» модем. Основываясь на теоретических знаниях и предположениях о совместимости различных типов микросхем памяти, я решил купить две микросхемы flash-памяти, с целью их прошивания и установки в модемы.
Ðèñóíîê 12. Äâå ìèêðîñõåìû flash-ïàìÿòè AM29F010B
№12(13), декабрь 2003
Далее, я зашёл на сайт фирмы ZyXEL и скачал оттуда последние версии прошивок для модемов. Для сокращения статьи я буду писать лишь про прошивку только одного модема ZyXEL U-1496+ (он же U-1496S+), так как прошивка двух других ничем не отличается, разве что версии программ для каждого типа модема свои. Воспользовавшись информацией из [13], я вставил в модем чистую микросхему flashпамяти, включил модем и набрал команду AT. Модем выдал «ok». Если у вас модем не включается, то, возможно, вам придётся вставлять микросхему памяти при включённом питании, но об этом и возможных проблемах далее. (Набор программ по прошивке можно скачать тут: [16].) Для записи новой прошивки необходим специальный загрузчик (flash loader). Так как передавать напрямую двоичные файлы, особенно с помощью стандартных терминалов, невозможно (часть символов будут считаться служебными командами), были придуманы несколько альтернативных, в том числе и текстовых, форматов. (Например, существует формат sb7. Этот формат прошивок, предназначенных для заливки во flash ПЗУ модемов Diamond Supra.) Наибольшее распространение получил текстовый формат S37, понимаемый модемами Acorp. Соответственно, имеются утилиты конвертации s37 ↔ bin, которые без проблем можно найти в Интернете. Программа загрузчика, загрузившись на модем, может позволить вам загружать прошивки по более удобному протоколу X-modem. Хотя, если у вас есть конвертор (bin → s37), то эта возможность может вам и не понадобиться. Если вы встретите файл формата s37, то его содержимое будет примерно следующее: S308000080004C0380A8 S3150000800378B2D533B20090C900F00287908AD05374 S3150000801398D050B79027907A68C900F011C901F03B .... S31500008CC2C947D0ED6820D383600000000000000091 S70500000000FA
Создавать свой загрузчик, может, и интересно, но зачем изобретать велосипед, берём готовый файл hsloader.s37 на сайте журнала: www.samag.ru/sourse/hsloader.37.zip (это доработанный загрузчик от Sergey.Korolew@p2.f4.n5053.z2. fidonet.org). Вместо hsloader.s37 можно взять uploader.s37 из [16]. Далее выполняем следующие действия по загрузке, краткая инструкция (модем у нас к этому моменту включён, ПЗУ вставлена и на команду AT он выдаёт «ok»): 1. Даём модему команду AT**. 2. Загружаем hsloader.s37 по протоколу ASCII, либо вставляем из буфера чтобы не набирать руками. 3. Загружаем прошивку в формате s37, также по протоколу ASCII. В некоторых случаях загрузчик не грузится без родной ПЗУ модема, поэтому смену ПЗУ на flash следует производить на лету после пункта 2. После замены следует нажать «G» (большое!) и перейти к пункту 3. Замечание: описанные выше инструкции я выполнил у себя с небольшим исключением, вместо AT**, я набирал AT**2, разницы между этими командами я для себя не уяснил, похоже, что можно прошивать разные микросхемы, не только flash, если кто знает – поделитесь, пожалуйста, ин-
69
hardware формацией. Вместо hsloader.s37 я использовал uploader.s37. Скачанный с ZyXEL файл: http://www.zyxel.ru/public/u-series/ 1496/firmware/6.22/rm622sp1.zip с нужной версией прошивки я успешно разархивировал и два файла rm622sp1.u24 и rm622sp1.u25 сконвертировал и прошил в две миросхемы flash памяти. После успешной прошивки я увидел надпись «Upload successfully completed».
Ðèñóíîê 13. Âèä òåðìèíàëüíîé ïðîãðàììû ïîñëå óñïåøíîé ïåðåïðîøèâêè
Аналогичным образом можно прошить любые другие версии программ для других устройств. Далее две прошитые микросхемы с новой версией я собрался установить в модем. При старой версии программы: ATI1
модем выдавал: 61694 U1496S V 6.12 P OK
После замены старых микросхем памяти на новые модем гордо показывал свою обновлённую версию как: 60837 U1496S
V 6.22 P
Ðèñóíîê 14. Íàäïèñü íà èíäèêàòîðå ïåðåïðîøèòîãî ìîäåìà «U1496S V 6.22 P»
70
На данном этапе задача номер 1 по обновлению программного обеспечения модемов была успешно нами выполнена. Замечание 1: при попытке прошить на модели с плюсом версию от модели без плюса всё прекрасно прошивалось. При попытке вставить в модем не его версию он ругался, выдавая надпись на экранчике о несоответствии версии. Замечание 2: после перепрошивки у меня модем U1496S+ отказался общаться с терминальной программой, хотя на индикаторе показывал успешно пройденные тесты и функционировал при управлении им через клавиши меню. Как выяснилось, произошло это потому, что почему-то в ячейке Character Length вместо значения 10 байт, обычно используемых по умолчанию, оказалось записано значение 8. Я перепроверил все остальные настройки и сохранил профиль. После этого даже после ATZ и выключения питания модем оставался в здравом смысле. Замечание 3: не знаю уж, насколько у меня плохая связь, но попытки установить связь с каким-либо из московских интернет-провайдеров не дали успеха, модем ни в какую не хотел соединяться. Понимая, что такого быть в принципе не может и проблема, видимо, в настройках, я покопался в инструкции [7], так как я далёк от всяких треллис-кодирований и полного досконального понимания происходящих явлений при установке соединений, я методом перебора выяснил что оптимальными настройками для соединения по моей линии (декадно-шаговая АТС) оказались команды: AT&N19 – выбор протокола v.32bis 7200/4800 для установления связи; AT&K4 – выбор протокола сжатия v.42bis и коррекции ошибок v.42; AT*E1 – устанавливать связь только с использованием протокола коррекции ошибок; ATX7 – выбор более информативной строки CONNECT при установке соединения. После них модем, как танк, соединялся на 7200. Возможно, поэкспериментировав, вы найдёте для себя оптимальными другие настройки. Для работы определителя номера советую дать команду AT&I4 – включить АОН, информация об определившемся номере будет выдаваться как до установки соединения, так и в строке CONNECT. Это очень удобно: знать номер звонящего при использовании модема для входящей связи. Замечание 4: скорость работы COM-порта следует выбирать 57600, ZyXEL серии 1496 не поддерживает работу на 115200. (Если хочется больше, можно попробовать 76800.) Замечание 5: дополнительная информация c [13] для желающих поэкспериментировать со своим модемом в вопросах перепрошивки: Во время перепрошивки не забудьте о необходимости сигнала WE на 31 выводе Flash. Во время замены ПЗУ, надо вытаскивать её аккуратно, если у вас нет соответствующего прибора, то, используя отвёртку, старайтесь
hardware вытаскивать ПЗУ равномерно. Имеется опасность перекоса ПЗУ в последний момент, когда она уже вынимается легко, и отгибания вбок крайних ног. Несмотря на то, что при перекосах возможны проблемы по опыту Dmitry. Yalin@p12.f638.n5020.z2.fidonet.org вставлять flash надо начиная с 16-17 ног таким образом, чтобы питание, т.е. 32 и 1 ноги попадали последними. В общем, вставлять её под небольшим наклоном. Вытаскивать ПЗУ соответственно наоборот, если же вставлять flash по-другому, то наблюдается в лучшем случае зависание терминальной программы, в худшем помогает только кнопочка reset. (Лично у меня, даже при наличии желания что-то повесить, такого не происходило, возможно, мне повезло.) Переставляя микросхемы подобным образом, вы можете испортить модем или Flash, так что вся ответственность за те или иные эксперименты лежит только на вас. Для того чтобы свести риск к минимуму, нужно либо установить ZIFsocket вместо вашей панельки под ПЗУ, либо соорудить конструкцию, подобную той, что описывает Dmitry Gzhibovsky (Dmitry.Gzhibovsky@p5.f52.n5080.z2.fidonet.org). Берётся любая микросхема с «работающей» прошивкой (хоть родное одноразовое ПЗУ), на неё сверху напаивается панель для flash. 22-ые ноги верхней панели и ПЗУ отгибаются и через резисторы сопротивлением порядка 10 КОм подключаются к +5 В. Далее, с 22-ой ноги панели, которая стоит в модеме, сигнал подается на переключатель. С переключателя сигнал идёт на те же 22-ые ноги ПЗУ и верхней панели, то есть переключатель подает сигнал с модемной панели или на ПЗУ, или на верхнюю панель, куда собственно flash-память и ставится. Далее вся эта конструкция втыкается в модем, переключатель в режим «ПЗУ», включаем питание, at**, заливаем специально доработанный для этих целей uploader, переключатель в положение «flash», нажимаем на клавиатуре «G», uploader просит залить прошивку, что с радостью и делаем. После того как все модемы оказались перепрошиты на новые версии, передо мной встала задача номер 2, а именно как подключить 3 или 4 модема к компьютеру и заставить их вместе работать под ОС Linux.
Несколько модемов Купить модемный пул на 8/16/32 и более модемов или соответствующую многопортовую плату от фирм Digiboard, Eqiunox, Granato, Cyclades, Moxa могут позволить себе не все, да и как-то бессмысленно покупать столь хитрые и дорогие устройства, если вам надо подключить всего лишь 3 модема, а не 16 или 32. Можно обойтись покупкой одного или нескольких переходников USB-COM. Хотя по цене не скажу, что выйдет дешевле. Также можно поискать старые дешёвые мультикарты, позволяющие гибко настраивать параметры встроенных в неё COM-портов, но это будет то же самое решение, что мы рассмотрим ниже. Физически нам ничего не мешает воткнуть в компьютер один или два внутренних модема и к двум внешним портам подключить ещё два внешних модема. Но работать вместе без особой настройки данный квартет или трио не будут.
№12(13), декабрь 2003
А в чём собственно проблема? Поняв суть проблемы, может, мы сможем решить или обойти её. Изучив по этому вопросу литературу, можно хорошую инструкцию от какого-нибудь модема или [17], мы можем выяснить, что для работы COM-порта, к которому подключаются модемы, либо которые встроены в сам модем, если он внутренний, необходимо иметь адрес, по которому будут производиться операции чтения и записи и прерывание, через которое будет регулироваться этот процесс. Надеюсь, что все понимают, что с точки зрения повышения производительности асинхронная запись оказывается более выгодной, чем синхронная. В своей основе это и порождает необходимость в существовании прерываний и вытекающие из этого проблемы. В наследство от MS-DOS стандартная настройка COMпортов оказывается следующей: /dev/ttys0 /dev/ttys1 /dev/ttys2 /dev/ttys3
(COM1), (COM2), (COM3), (COM4),
port port port port
0x3f8, 0x2f8, 0x3e8, 0x2e8,
irq irq irq irq
4 3 4 3
Замечание: для меня, кстати, до сих пор является секретом, почему в моей любимой терминальной программе Telemate под DOS имеется возможность выбора COM1COM8. Мне интересно понять, как разработчикам виделось использование, скажем, COM7 или COM8. Если вы уже заметили, то прерывания у COM1 и COM3, COM2 и COM4 совпадают. В этом как раз и состоит основная проблема. Из-за существующих ограничений в силу особенностей реализации ранее придуманной AT/ISA архитектуры одно прерывание нормально не может использоваться одновременно двумя или несколькими COMпортами. Если же подключить несколько СОМ-портов на одно прерывание и попытаться работать с ними всеми одновременно, возникнут сбои, ошибки и зависания. Данные ограничения можно обойти путём использования специальных многопортовых карт, о которых я упомянул выше. Эти карты умеют делить одно прерывание между несколькими портами. Кстати, большинство из них поддерживается Linux/FreeBSD. Соответственно правильным решением, по которому мы пойдём, является поиск свободных прерываний и развод модемов, чтобы используемые ими прерывания не пересекались. Обычно старые внутренние модемы имеют разъём ISA 8-bit (именуемый также PC). Выбор прерывания на такой шине значительно ограничен по сравнению с полной ISA (16-bit). А с учётом, что не все прерывания могут быть использованы, модемы очень редко предоставляют возможность выбора большего, чем 4 числа прерываний. При этом используются прерывания по умолчанию, закреплённые за параллельными и последовательными портами: IRQ IRQ IRQ IRQ
3: 4: 5: 7:
COM2 COM1 LPT2 LPT1
У ZyXEL 1496E+ с помощью перемычек (jumpers) можно выбрать следующие параметры:
71
hardware
Ðèñóíîê 15. Ñõåìà âûáîðà àäðåñà COM-ïîðòà è ïðåðûâàíèÿ ñ ïîìîùüþ ïåðåìû÷åê íà ìîäåìàõ ZyXEL U1496B+
Если же вам повезло и у вас модем более продвинутый, а ещё и 16-битный, то вам станут доступны все прерывания, в том числе верхние 10-15. Не все прерывания можно выбрать и использовать, поэтому, скорее всего, для вас окажется более полезной следующая информация по выбору прерываний. Стандартное использование прерываний следующее: IRQ 0 – Таймер, канал 0. IRQ 1 – Клавиатура. IRQ 2 – Cascade for controller 2. IRQ 3 – Последовательный порт 2 (COM2). IRQ 4 – Последовательный порт 1 (COM1). IRQ 5 – Параллельный порт 2 (LPT2). IRQ 6 – Накопитель на гибких дисках. IRQ 7 – Параллельный порт 1 (LPT1). IRQ 8 – Часы реального времени. IRQ 9 – Перенаправлено на IRQ2. IRQ 10 – Не назначено. IRQ 11 – Не назначено. IRQ 12 – Не назначено. IRQ 13 – Математический сопроцессор. IRQ 14 – Первый контроллер жёстких дисков. IRQ 15 – Второй контроллер жёстких дисков. Использовать можно любое неиспользуемое прерывание, однако следует понимать, что есть прерывания, которые всегда заняты и соответственно без конфликтов в системе при их использовании обойтись нельзя. Данный факт значительно сужает диапазон нашего выбора, но кто же несколько лет назад знал, что прерываний будет катастрофически не хватать, как не хватает сейчас пропускной способности московской подземки и автомобильных дорог. Давайте рассмотрим, чем мы можем смело пользоваться, а от чего придётся воздержаться. Без сомнения, прерывание 0 использовать не получится. Прерывание 1 при особых усилиях можно попытаться использовать. Зачем на сервере клавиатура, ибо можно подключить её по USB, либо вообще управлять компьютером по сети. Однако столь радикальные меры можно позволить на давно отлаженных системах, где клавиатура точно не нужна. Посему для большинства это прерывание также окажется закрытым для использования. Прерывание номер 2 зарезервировано за неким хитрым устройством, которого, как и людей, его использующих, я никогда не видел. Так что вполне можно использовать это прерывание для своих нужд. Следует учесть, что 2-е и 9-е прерывание в силу особенностей реализации идентичны
72
друг другу, если не сказать честно, что это одно и то же прерывание, а поэтому использовать их вместе никак не получится. Прерывания 3 и 4 у нас уже заняты двумя внешними COM-портами, к которым мы уже подключили два модема. IRQ 5 – редко кто у себя на компьютере использует его по прямому назначению, а именно для организации второго параллельного порта. Хотя, несомненно, это удобно – развести устройства в случае, если у вас на одном параллельном порту висят одновременно: ФАКС (комбайн), принтер, card reader и сканер. Появление USB частично решило эту проблему, однако никто же не будет бесплатно менять все используемые устройства на их USB-аналоги, а также переписывать коды предыдущих версий ОС, в которых нет поддержки USB. Иногда на это прерывание вешают звуковую карту. Если у вас нет ничего из вышеописанного, то это прерывание для вас открыто. IRQ 6 используется дисководом. Не секрет, что многие, покупая новые компьютеры, не ставят туда дисковод не потому, что им жалко лишние 180 рублей, а потому, что он им не нужен. На серверах можно также обойтись без дисковода. Посему, если отключить соответствующий контроллер в BIOS, данным прерыванием можно смело пользоваться. IRQ 7 – это скорее принтерное прерывание, лишь потому, что чаще всего на первый параллельный порт, использующий это прерывание, устанавливают принтер. Соображения тут аналогичны LPT2. Если у вас порт не используется, то прерывание можно смело использовать. IRQ 8 – часы реального времени, использовать это прерывание вряд ли получится. IRQ 9 – см. IRQ 2. IRQ 10-12 если не используются, то мы можем забрать их под свои нужды. IRQ 13 отвечает за математический сопроцессор. Если ваш процессор более чем 486 DX2, то есть имеет встроенный сопроцессор, то вряд ли вы сможете использовать это прерывание, однако если у вас стоит какаянибудь 386 или 486 без сопроцессора, то это прерывание для вас открыто. IRQ 14 – вряд ли вы обойдётесь без жёсткого диска, поэтому данное прерывание скорее всего будет для вас занято. Хотя, если пользоваться только дисководом (дискетные версии Linux или других ОС), либо сетевой картой (полная загрузка по сети) или отдельным SCSI-котроллером, то при особых усилиях можно это прерывание задействовать для своих нужд. IRQ 15 – если у вас не используется и отключён второй контроллер IDE (CD-ROM и винчестер висят на одном шлейфе), то без проблем можно использовать и это прерывание. В общем, не пусто, но и не густо. В целом, если не вдаваться в описанную выше экзотику, то с большой вероятностью вы не сможете использовать IRQ 0, 1, 6, 8, 13 или 14. Они будут использоваться вашей материнской платой. Используя их необдуманно и не по назначению, вы можете заработать множество неприятностей. Когда вы закончите ваши эксперименты, посмотрите в /proc/ interrupts (если в ядре есть поддержка /proc) и удостоверьтесь, что конфликтов нет. Выбрав для себя, что для третьего модема следует использовать IRQ 5, я установил перемычки на модеме ZyXEL в следующее положение и вставил модем в компьютер.
hardware Соответственно, помимо установки файлов, отвечающих за сообщение ядру нужных параметров во время загрузки. Операцию по указанию этих самых нужных параметров следует хотя бы один раз выполнить вручную. В моём случае это была команда: Ðèñóíîê 16. Âûáîð êîíôèãóðàöèè àäðåñ=3E8, IRQ 5 ñ ïîìîùüþ ïåðåìû÷åê
В BIOS внешние COM1 и COM2 я назначил стандартно. В результате у меня получилась следующая «железная» конфигурация: COM1 - Port: 0x03f8, IRQ: 4 (/dev/ttyS0) COM2 - Port: 0x02f8, IRQ: 3 (/dev/ttyS1) COM3 - Port: 0x03e8, IRQ: 5 (/dev/ttyS2)
Соответственно, если первые два порта Linux определит сам, так как они стандартны, то что же касаемо COM3, то ядру Linux надо будет дать пояснение, чтобы оно знало, где именно искать наш COM3. В качестве программы, объясняющей ядру, что и где из COM-портов находится, в Linux используется setserial. Следует заметить, что эта программа ничего не устанавливает сама, она просто сообщает ядру о тех настройках, о которых вы её попросите. Файл конфигурации последовательных портов в некоторых версиях Linux по умолчанию находится в директории /etc и называется serial.conf. Для описанной выше конфигурации у меня он получился следующего содержания: /dev/ttyS0 115200 /dev/ttyS1 115200 /dev/ttyS2 115200
# setserial /dev/ttyS2 irq 5
Сменяющая стандартно ассоциированное IRQ 4 для COM3 на выбранное мной IRQ 5. Следующие команды проверяют правильность установки (выводят настройки на экран, чтобы вы могли их проверить сами) и сохраняют имеющуюся конфигурацию, как это было описано выше: # # # #
setserial /dev/ttyS0 setserial /dev/ttyS1 setserial /dev/ttyS2 /etc/rc.d/init.d/serial stop
У меня получилась следующая конфигурация: COM1 /dev/ttyS0, UART: 16550A, Port: 0x03f8, IRQ: 4 COM2 /dev/ttyS1, UART: 16550A, Port: 0x02f8, IRQ: 3 COM3 /dev/ttyS2, UART: 16550A, Port: 0x03e8, IRQ: 5
Замечание 1: пока я в BIOS не проассоциировал руками прерывание номер 5 с шиной ISA, в которую был установлен модем, модем не виделся.
uart 16550A port 0x03f8 irq 4 baud_base ↵ spd_normal skip_test uart 16550A port 0x02f8 irq 3 baud_base ↵ spd_normal skip_test uart 16550A port 0x03e8 irq 5 baud_base ↵ spd_normal skip_test
Заглянув в директорию с документацией от Red Hat Linux v.7.3 /usr/share/doc/setserial-2.17q, можно увидеть там два файла: README и rc.serial, вот поистине правда: RTFM и станете умнее. Естественно, что в случае нестандартной конфигурации запускать setserial во время начальной загрузки вам придётся постоянно. Запускать его руками не есть хорошее решение, прописывать файл в /etc/rc.d/rc.local тоже не стоит, поэтому наиболее элегантным решением будет использование уровней загрузки и rc?.d директорий. В README написано, что файл rc.serial следует поместить в /etc/rc.d/init.d (переименовав просто в serial) и сделать на него ссылки из rc?.d либо руками, либо командой: # chkconfig --add serial
У второго способа есть особенности. При запуске /etc/ rc.d/init.d/serial с параметром stop или save осуществляется запись существующей конфигурации в /etc/serial.conf, причём туда попадают и все лишние устройства. Мне это показалось не очень удобным, поэтому я удалил файлы /etc/rc.d/ rc?.d/K??serial, осуществляющие ненужное мне сохранение, и удалил лишние сохранённые строчки из /etc/serial.conf. Конечно, сделав так, через годик-другой можно забыть про эту особенность, но будьте начеку и тренируйте память. Очень плохо, когда всегда и все настройки идут по шаблону, даже там, где это особо не нужно.
№12(13), декабрь 2003
Ðèñóíîê 17. Çàêðåïëåíèå ïðåðûâàíèÿ íîìåð 5 çà óñòðîéñòâàìè øèíû ISA
Замечание 2: запуск программы kudzu, осуществляющей поиск нового оборудования, следует производить после установки параметров последовательных портов, то есть после serial, чего при установке по умолчанию не наблюдается. Если вы хотите, чтобы kudzu обнаружил модем, запущенный у вас нестандартно на COM3 и после не терял его, сообщая вам, что устройство удалено из компьютера, то вам придётся поменять номер запуска kudzu на более высокий, например, с 05 на 51. Сделать это можно просто, удалив старые ссылки, запустив для этого: # chkconfig --del kudzu
Затем подправив 05 на 51 в /etc/rc.d/init.d/kudzu и создав новые ссылки: # chkconfig --add kudzu
73
hardware Если данное решение неудобно, то можно просто руками переименовать все файлы S05kudzu в директориях /etc/rc.d/rc?.d на S51kudzu. Скорее всего, изменение уровня запуска kudzu ни на что другое не повлияет. Убедиться в том, что все модемы установлены и доступны для дальнейшей настройки использующих их приложений, можно с помощью стандартной терминальной программы minicom. Если модем будет правильно реагировать на передаваемые ему команды, скорее всего, он работает. Для большей надёжности в правильной работе всех модемов, несомненно, следует проверять работу всех модемов одновременно, но из-за сложности подобной реализации мы опустим этот тест, ограничившись проверкой на жизнеспособность каждого модема по отдельности. Если у вас не установлена терминальная программа minicom, установите её (или используйте свою). В RedHat Linux v.7.3 она находится на 2-м диске (RHL v.9 – на 1-м). Запустите: # minicom -s
в появившемся меню:
Ðèñóíîê 18. Îêíî êîíôèãóðàöèè ïîñëå çàïóñêà "minicom -s"
Выберите Serial port setup, у вас выскочит новое окно:
Ðèñóíîê 19. Íàñòðîéêà ïàðàìåòðîâ COM-ïîðòà
Нажав «A», исправьте используемый вами порт на нужный и установите скорость на 57600. Нажмите «Enter» для выхода из подменю. В случае необходимости сохраните конфигурацию – пункт «Save setup as dfl» и, нажав «ESC», запустите терминал. На некоторое время у вас выскочит надпись Initializing Modem. После чего у вас должна появиться строка, где, как обычно, можно набирать AT-ко-
74
манды. (Например, ATI или ATI1.) Выход из терминала «CTRL-A, Q». Повторив вышеописанные операции по отношению ко всем остальным модемам, можно также убедиться, что они работают. Если это так, то значит подключение 3 модемов прошло у вас успешно и далее вы можете настраивать другие программы, прописывая в них модемы просто как устройства /dev/ttyS0, /dev/ttyS1, /dev/ttyS2.
Литература, ссылки: 1. Хоровиц П., Хилл У. Искусство схемотехники: Пер. с англ. – Изд. 6-е – М.: Мир, 2003. 2. Гальперин М.В. Электронная техника: Учебник. – М.: ФОРУМ: ИНФРА-М, 2003. 3. Фрике К. Вводный курс цифровой электроники – М.: Техносфера, 2003. 4. Жеребцов И.П. Основы электроники – 5-е изд., перераб. и доп. – Л.:Энергоатомиздат. Ленинградское отделение, 1989. – 122-123 с. 5. Лукацкий А.В. Обнаружение атак. – СПб: БХВ-Петербург, 2001. – 624 с. 6. Закляков П. Плохое электропитание, или «Грабли» с UPS. //журнал «Системный администратор», №8(9), 2003 г. – 52-61 с. 7. Руководство для пользователей. Универсальный модем серии U-1496. Документ № 83011501, Версия 2.21 ZyXEL Communications Corporation и АО МКЦ «Вариант» 8. Доска объявлений по купле/продаже/обмену: http:// www.komok.com 9. Доска объявлений по продаже.(интернет-аукцион): http://www.molotok.ru 10. Каталог продукции фирмы ZyXEL: http://www.zyxel.ru/ techsup/zyx_fil.asp 11. Учебник по теме «Микропроцессоры». Постоянные запоминающие устройства. http://docs.lab127.karelia.ru/ hardware/microcpu/pam1.htm 12. Информация о некоторых видах памяти. http:// digital5.ece.tntech.edu/Public/611/Clements%20CDROM/ DATA/HITACHI/A_RAM.PDF 13. Как менять прошивку на модемах Acorp: http:// pirogoff.chat.ru/rockwell/firm.htm 14. Официальный сайт Митинского городского радиорынка (г. Москва): http://www.tkmitino.ru/ 15. Сайт сети магазинов «Чип и Дип» по продаже электронных компонентов, цены, наличие, справочная информация. http://www.chip-dip.ru 16. Набор программ для прошивки flash-памяти в Acorp модемах: http://pirogoff.chat.ru/files/firmware.zip 17. man setserial
web
АЛЕКСЕЙ МИЧУРИН 76
web Постановка задачи. Или в чем проблема? Многие веб-мастера часто сталкиваются с задачей конвертирования файлов Microsoft Excel в другие форматы. Нередко это сопряжено с трудностями, так как формат xls, как все прекрасно знают, не документирован. В некоторых случаях возможно сохранение данных Excel в документированных форматах и последующая их обработка. Но часто этот способ работает неудовлетворительно. Простые форматы, удобные для обработки, не способны сохранить всю информацию о форматировании документа, а реализация обработчика сложных форматов неоправданно трудоёмка. За примером далеко ходить не надо. Множество фирм, которые имеют свои веб-страницы и периодически их обновляют, ведут свои дела с использованием Excel. Перед веб-мастером при каждом обновлении информации на сервере возникает задача конвертирования. Причём задача может осложняться следующими аспектами: Во-первых, это изменение дизайна. Price-list, подготовленный в Excel, обычно рассчитан на распечатку на чёрнобелом принтере. Price-list на веб-сайте – нет. Хотя бы поэтому простое «Сохранить как веб-страницу» не подходит (я уж молчу о том, какого качества получается HTML-код при таком сохранении). Во-вторых, при конвертировании необходимо учесть специфику Excel. Например, очень многие люди, редактирующие price-list, широко применяют команду «Формат/строка/ скрыть». При этом высота строки становится нулевой, и строка как бы исчезает с экрана и на печати. Понятно, что и на веб-сайт такие строки попасть не должны. Однако они превосходно сохраняются в других форматах и ничем не отличаются от обычных, не скрытых, строк. Это приводит к тому, что доктрина «Сохранить как текст с разделителями и обработать» не даёт удовлетворительных результатов. В-третьих, в price-list часто используется форматирование, сохранение которого критично. Например, наименования некоторых товаров могут быть зачёркнуты или выделены цветом в знак того, что эти товары были и обязательно будут, но сейчас их нет. Некоторые позиции могут быть выделены курсивом и так далее. Вся эта информация бесследно исчезает, если пересохранить price-list в простом формате, скажем, как текст с разделителями табуляции. Итак, наша задача состоит в том, чтобы корректно конвертировать документ из формата xls в формат HTML с учётом форматирования исходного документа и при этом обойтись «малой кровью». Я предлагаю разбить эту задачу на две. Первая – сохранение данных в простом формате, который тем не менее будет нести в себе всю необходимую нам информацию о разметке документа. Вторая – обработка этого формата и создание HTML-страницы. Первую задачу (экспорт) я предлагаю решить средствами Excel. Тут у нас фактически нет выбора, формат xls может обработать только то единственное на свете приложение, которое его понимает. Это диалектика. Вторую задачу я предлагаю решить средствами языка Perl. Почему? Потому, что этот язык ориентирован на работу со строками и на решение задач, подобных нашей (Perl – Practical Extraction and Report Language – то, что надо). Пото-
№12(13), декабрь 2003
му, что этот язык знает достаточно много программистов, связанных с веб-разработками (если вы не относитесь к их числу и планируете заниматься web, то искренне рекомендую обратить внимание на Perl). Потому, что этот язык бесплатен и доступен любому пользователю на любой платформе. И потому, что мой код на Perl можно будет потом легко модифицировать, заставив его, допустим, помещать каждый раздел price-list в отдельный файл, различным образом сортировать позиции прайса, отслеживать обновления и динамику цен, снабжать каждую позицию полями HTMLформ для on-line заказа в веб-магазине... В конце концов, мой скрипт легко превратить в CGI-приложение для администрирования веб-сервера. Такое решение представляется мне максимально гибким, функциональным и компактным, потому что каждая часть задачи решается тем средством, которое наиболее приспособлено для её решения. Давайте оттолкнёмся от конкретного примера. В качестве «подопытного кролика» предлагаю следующий прайс:
Как видите, он сочетает в себе все неприятные элементы, упомянутые выше: и форматирование (фон, перечёркивания, жирный шрифт), и скрытые строки (если приглядеться, то можно заметить, что после девятой сразу идёт двенадцатая строка). Давайте им займёмся.
Экспорт данных из Excel Приступим к решению первой задачи. Для экспорта данных из Excel я предлагаю несложный макрос на Visual Basic (номера строк приведены только для удобства комментирования): 1: Sub table2table() 2: ' 3: ' ìàêðîñ, ñîõðàíÿþùèé âûäåëåííûé ôðàãìåíò òàáëèöû 4: ' â òåêñòîâîì ôîðìàòå ñ îòìåòêàìè î ôîðìàòèðîâàíèè 5: ' 6: With ActiveWindow.RangeSelection 7: c1 = .Columns.Column 8: c2 = .Columns.Count - 1 + c1 9: r1 = .Rows.Row 10: r2 = .Rows.Count - 1 + r1 11: End With 12: If (r1 - r2 = 0 And c1 - c2 = 0) Then 13: MsgBox _ 14: "÷òî-òî ìàëî âûäåëåíî (äëÿ ñîõðàíåíèÿ) ,-)", _ 15: vbCritical, "ñîîáùåíèå ìàêðîñà" 16: End If 17: fileSaveName = Application.GetSaveAsFilename( _ 18: InitialFileName:="file", _ 19: fileFilter:="Text Files (*.txt), *.txt", _ 20: Title:="ñîõðàíåíèå ñòðàíèöû â íàøåì ôîðìàòå") 21: If fileSaveName = False Then
77
web 22: MsgBox _ 23: "ôàéë-òî íå âûáðàí. íèêàêèõ äåéñòâèé íå ïðåäïðèíÿòî.", _ 24: vbCritical, "ñîîáùåíèå ìàêðîñà" 25: Else 26: sep = Chr(9) ' ðàçäåëèòåëü 27: subsep = Chr(8) ' ïîä-ðàçäåëèòåëü 28: Open fileSaveName For Output As #1 29: For r = r1 To r2 30: l = CStr(Rows(r).RowHeight) 31: For c = c1 To c2 32: With Cells(r, c) 33: l = l + sep + CStr(.Text) + _ 34: subsep + CStr(.MergeCells) + _ 35: subsep + CStr(.Font.Bold) + _ 36: subsep + CStr(.Font.Strikethrough) 37: End With 38: Next 39: Print #1, l 40: Next 41: Close #1 42: End If 43: End Sub
Этот макрос сохраняет выделенную часть прайса в заданный файл. Макрос можно добавить к рабочей версии прайса и сделать для его вызова кнопку (вне области печати), а можно хранить в отдельном файле. Поместить его в документ очень просто: вызовите редактор Visual Basic (меню: сервис → макрос → редактор Visual Basic; или Alt-F11), создайте новый модуль (меню: вставить → модуль) и введите приведённый здесь текст (без номеров строк). Теперь можно нарисовать кнопку (инструмент на панели «Формы») и назначить ей макрос. Давайте вкратце рассмотрим, как работает этот код. Первая строка – объявление макроса. Как видите, я назвал его незамысловато table2table, вы можете наречь его более звучно. В строках с 6 по 11 мы определяем границы выделенной части документа (ведь мы будем сохранять только выделенную часть). Теперь c1 и c2 – номера первого и последнего столбца, а r1 и r2 – первой и последней строки выделенной области. Далее, в строках с 12 по 16 проверяем, а была ли выделена область или нашему макросу предстоит работать только с одной ячейкой. Этого, конечно, можно и не делать, но ведь, скорее всего, запускать этот макрос будете не вы, а менеджеры, редактирующие прайс, на их аккуратность не всегда можно рассчитывать. Итак, если ничего не было выделено, то наш макрос выдаст предупреждение:
В строках с 17 по 20 мы вызываем диалог Application. GetSaveAsFilename, чтобы пользователь мог выбрать имя файла:
78
Опять же вы можете просто задать фиксированное имя, но мне кажется, что это неудобно даже в том случае, если вы сами эксплуатируете этот макрос. В строках с 21 по 42 следует конструкция if-then-else с проверкой, было ли указано имя файла для сохранения или пользователь нажал кнопку «Отмена» диалога «Сохранить как...». Если пользователь отказался от сохранения, то выдаётся соответствующее сообщение (строки с 22 по 24), если имя файла указано, то начинается самое интересное – сохранение данных. Но прежде чем обсудить процедуру сохранения (строки с 26 по 41), давайте скажем пару слов о том, в каком же именно формате мы намерены сохранять данные. Предлагаю самый простой для обработки формат: ASCIIтекст. Каждая строка соответствует строке сохраняемой таблицы. Поля разделены односимвольными разделителями. Первое поле – высота строки (эта информация необходима, чтобы отфильтровать «скрытые» строки). Все последующие поля – содержимое ячеек, но каждое из этих полей содержит несколько под-полей, разделённых своими разделителями. Под-поля несут различную информацию о ячейке: содержание, параметры форматирования. У нас разделители полей и под-полей задаются ASCII-кодами в строках 26 и 27 соответственно. Вы можете выбрать более удобные разделители. Например, если вы уверены, что в ваших данных никогда не встречается символ «:», то можно взять его в качестве разделителя или под-разделителя. Далее (строка 28) открываем файл. Организуем цикл по строкам (строка 29). Для каждой строки вычисляем высоту. Заодно начинаем готовить строку для сохранения в файл в переменной l (строка 30 листинга). В цикле (строка листинга 31) по ячейкам сохраняемой строки таблицы добавляем к строке l всю интересующую нас информацию о ячейках, снабжая её разделителями. Какие свойства ячейки мы сохраняем? Первым делом – текст ячейки. Обратите внимание, что мы используем именно свойство .Text, а не свойство .Value. Это не случайно. Свойство .Value возвращает истинное содержимое ячейки, свойство .Text возвращает тот текст, который отображается на мониторе и выводится на печать. Эти две величины могут не совпадать (и обычно не совпа-
web дают), потому что на экран значения выводятся согласно заданному формату ячейки (например, числа выводятся с заданным количеством знаков после запятой). Свойство .MergeCells говорит о том, является ли ячейка частью группы объединённых ячеек. Свойство .Font.Bold отражает жирность текста в ячейке. Свойство .Font.Strikethrough говорит о том, был ли текст оформлен как зачёркнутый. Для нашего примера нам, пожалуй, больше ничего не потребуется. Однако не могу не отметить ряд полезных свойств, которые могут вам пригодиться. Имена этих свойств достаточно красноречивы, и я не буду их комментировать, ограничусь перечислением: .Font.Name .Font.FontStyle .Font.Size .Font.Underline .Font.ColorIndex .Font.Italic .HorizontalAlignment .VerticalAlignment .ColorIndex .Pattern Обратите внимание, все свойства явно приводятся к строчному типу функцией CStr (строки с 33 по 36). Это весьма полезная процедура, навсегда избавляющая вас от головной боли о преобразованиях типов. Здесь следует сделать важную оговорку. Дело в том, что функция CStr не в состоянии обработать неопределённые значения. Если таковые будут встречаться в ваших документах, то вместо CStr вы можете использовать собственную функцию преобразования величин в текстовый формат. Например, safeCStr: 1: Function safeCStr(p As Variant) As String 2: If IsNull(p) Then safeCStr = "" Else safeCStr = CStr(p) 3: End Function
(Должен отметить, что сам я никогда не сталкивался с такими ситуациями, но научно-технический консультант журнала без труда нашёл в Интернете прайс-лист, в некоторых ячейках которого свойство .Font.Bold было не определено. Я полагаю, что такие документы могут возникать в результате экспорта данных из других приложений. Например, продукты 1C допускают экспорт данных в Excel. Одним словом, такая ситуация возможна. – Примечание автора.) Вот почти и всё. Осталось сохранить готовую строку l в файл (строка 39 листинга) и закрыть файл по завершении всего цикла по строкам (строка 41). Итак, вы выделяете сохраняемую область (в нашем примере это первые три столбца таблицы, строки с 4 по 21), нажимаете созданную вами кнопку, выбираете имя файла, и файл сохранён. Что с ним делать дальше?
Создание HTML-страницы по экспортированным данным С этим файлом можно сделать всё что угодно, потому что его формат нам полностью известен (приятно это осознавать). Я приведу пример генерации HTML-страницы.
№12(13), декабрь 2003
Как я и говорил, предлагаю скрипт на Perl: 1: #!/usr/bin/perl -w 2: 3: #use strict; 4: 5: # my ($TRUE, $FALSE)=('Èñòèíà', 'Ëîæü'); 6: my ($TRUE, $FALSE)=('True', 'False'); 7: 8: sub qtnum { 9: my $t=shift; 10: $t=~s|,(\d+)|,<small>$1</small>|; 11: return $t; 12: } 13: 14: sub qtstring { 15: my $t=shift; 16: $t=~s/\&/\&amp;/g; 17: $t=~s/\"/\&quot;/g; 18: $t=~s/\>/\&gt;/g; 19: $t=~s/\</\&lt;/g; 20: return $t; 21: } 22: 23: print <<'TEXT'; 24: <html> 25: <head> 26: <title>ïðàéñ íåêîé ôèðìû</title> 27: <style type="text/css"> 28: <!-29: .al {background-color: #FFFFFF} 30: --> 31: </style> 32: </head> 33: <body bgcolor="#E8E8E8"> 34: <table cellspacing="0" cellpadding="1" border="0"> 35: <tr><td colspan="3" height="1" bgcolor="#8F0000" ↵ nowrap></td></tr> 36: <tr> 37: <th colspan="3" bgcolor="#FFFFFF"><big>ïðàéñ íåêîé ↵ ôèðìû</big></th> 38: </tr> 39: <tr><td colspan="3" height="1" bgcolor="#8F0000" ↵ nowrap></td></tr> 40: <tr> 41: <th rowspan="3">íàèìåíîâàíèå òîâàðà</th> 42: <th colspan="2"><small>öåíà</small></th> 43: </tr> 44: <tr><td colspan="2" height="1" bgcolor="#8F0000" ↵ nowrap></td></tr> 45: <tr> 46: <th><small>ó.å.</small></th> 47: <th><small>ðóá.</small></th> 48: </tr> 49: <tr><td colspan="3" height="1" bgcolor="#8F0000" ↵ nowrap></td></tr> 50: TEXT 51: 52: while (<>) { 53: s/[\x0A\x0D]+$//; 54: my @f=split /\x09/; 55: my $lh=shift @f; 56: my ($name, $usd, $rub)=map {[split /\x08/]} @f; 57: if ($lh) { 58: if ($name->[1] eq $TRUE) { # îáðàáîòêà çàãîëîâêà ðàçäåëà 59: print '<tr><th colspan="3" bgcolor="#FFFF00">' . 60: $name->[0] . 61: "</th>\n"; 62: } else { # îáðàáîòêà îáû÷íîé ñòðîêè 63: print <<'TEXT' . 64: <tr 65: onMouseOver="this.className='al';" 66: onMouseOut="this.className = '';"><td> 67: TEXT 68: ($name->[3] eq $TRUE?'<font ↵ color="#888888"><strike>':'') . 69: qtstring($name->[0]) . 70: ($name->[3] eq $TRUE?'</strike></font>':'') . 71: qq|</td>\n<td align="right">| . 72: ($usd->[2] eq ↵ $TRUE?'<font color="#880000"><b>':'') . 73: qtnum($usd->[0]) . 74: ($usd->[2] eq $TRUE?'</b></font>':'') . 75: qq|</td>\n<td align="right">| . 76: ($rub->[2] eq ↵ $TRUE?'<font color="#880000"><b>':'') . 77: qtnum($rub->[0]) .
79
web 78: ($rub->[2] eq $TRUE?'</b></font>':'') . 79: "</td>\n"; 80: } 81: print <<'TEXT'; 82: </tr> 83: <tr><td colspan="3" height="1" bgcolor="#8F0000" ↵ nowrap></td></tr> 84: TEXT 85: } else { 86: warn 'hidden line: '.$name->[0]."\n"; 87: } 88: } 89: 90: print <<'TEXT'; 91: </table> 92: </body> 93: </html> 94: TEXT
Скрипт принимает входные данные из файла, указанного как параметр командной строки, или со стандартного ввода и выдаёт HTML-код на стандартный выход. То есть запускать его можно так: perl file2html.pl file.txt >file.html
или, например, так: cat file.txt | perl file2html.pl >file.html
Разберёмся, как работает этот скрипт (я буду предполагать, что читатель немного знаком с Perl). Первая строка – стандартная магическая строка любого UNIX-сценария. Пользователи Windows могут её проигнорировать. В третьей строке – закомментированная инструкция use strict. Она будет полезна вам только при отладке. В строках 5 и 6 мы определим переменные $TRUE и $FALSE, которые будут содержать значения истины и лжи, выдаваемые Excel. Дело в том, что русский Excel использует русские слова, европейский – английские. Откомментируйте подходящую вам строку и закомментируйте лишнюю. Процедура qtnum (с 8 по 12 строки) добавляет к записи числа теги, превращая «3,14» в «3,<small>14</small>». То есть центы и копейки будут отображаться меньшим шрифтом. Это чисто косметическая мера. Процедура qtstring (строки с 13 по 21) квотирует «небезопасные» символы: & (and), “ (двойная кавычка), < (больше), > (меньше). Это, как вы понимаете, обязательная мера. В строках с 23 по 50 печатается «шапка» HTML-документа. В цикле while (строки с 52 по 88) мы считываем построчно входной файл, преобразуем его в HTML-документ и выдаём в стандартный поток вывода stdout. В строке 53 от очередной считанной строки отрезается символ(ы) конца строки. Я не использую стандартные функции Perl chop и chomp, потому что обрабатываемый файл создаётся под Windows, а обработчик (наш сценарий на Perl) может работать и под UNIX. Файл же может передаваться весьма экзотическими путями. Например, наверняка многие захотят чуть доработать мой код и превратить его в CGI-приложение для администрирования их родного сервера. Поэтому я не полагаюсь на стандартные функции, а прописываю явно, что мне необходимо удалить все символы \x0A и \x0D в конце строки. Далее строка разделяется на поля (строка 54). Здесь
80
используется тот же разделитель, что и в макросе на Visual Basic (строка макроса 26). Первое поле – высота строки – сохраняется в переменной $lh (строка 55). Все остальные поля разделяются на подполя. В результате переменным $name, $usd, $rub присваиваются указатели на массивы, содержащие всю необходимую информацию о содержимом и форматировании соответствующей ячейки. $name – ячейка с наименованием товара, $usd – ячейка с ценой в долларах, $rub – ячейка с ценой в рублях. Делается это одной-единственной строкой 56. Если высота строки не равна нулю, то выполняем блок с 58 по 84 строки. В противном случае выдаём предупреждение в стандартный поток ошибок stderr о том, что обнаружена и проигнорирована скрытая строка (строка 86). Обработка строк таблицы только на первый взгляд может показаться сложной. Прежде всего мы выясняем, с чем мы имеем дело: в строке 58 проверяем истинность свойства .MergeCells ячейки с наименованием товара. Если эта ячейка объединена, то это заголовок раздела, тогда выполняется код генерирующий заголовок (строки с 59 по 61). Если оказывается, что мы имеем дело с обычной строкой, то выполняется блок else (строки с 63 по 79). Здесь формируется строка HTML-таблицы, в которую вставляются дополнительные элементы форматирования (для тех строк таблицы, где это необходимо). Обратите внимание, что мы встроили в наш документ элементарный DHTML-приём. В таблице всегда подсвечивается строка, на которой находится указатель мыши. Это упрощает чтение таблицы. Согласитесь, что добиться такого эффекта средствами Excel (путём сохранения документа как веб-страницы) затруднительно. В строках 90–94 выводим завершающие теги документа. Обратите внимание, что в конце файла с программой обязательно должна быть пустая строка. Иначе последнее слово («TEXT») (строка 94) не будет правильно обработано интерпретатором Perl. То что получается на выходе, смотрите на рисунке (стр. 82). Согласитесь, было за что биться!
BUGS. Что ещё можно добавить? Я не сомневаюсь, что хотя мои примеры полностью работоспособны, мало кто будет использовать их без малейших модификаций. Хочу подбросить пару мыслей о том, что можно улучшить в этих скриптах, чтобы при их модификации вы не делали лишней работы, а убивали сразу как можно больше зайцев.
По сценарию на Visual Basic Здесь вам скорее всего придётся изменить набор сохраняемых параметров ячейки. Список наиболее полезных я привожу в обсуждении этого сценария. Если вам понадобится какая-нибудь экзотика, обращайтесь к документации Microsoft, свойства объекта Range. Наверное, многие сочтут недоработкой то, что макрос безусловно заменяет существующие файлы (если вы укажите для сохранения существующий файл). Это, как вы понимаете, легко исправить.
web
Наверное, для реальных документов будет несложно сформулировать условия, по которым макрос будет сам определять область прайса (или другого документа), подлежащую сохранению. Тогда этот процесс можно автоматизировать. Моё решение (сохранение выделенной области) скорее универсально, чем удобно. Наконец, читатель может справедливо спросить, зачем макрос для Excel сохраняет скрытые строки, ведь их можно отсеять уже на стадии экспорта? Снимаю шляпу перед внимательностью читателя (втайне надеясь на ответный жест в адрес моей проницательности). Сохранять скрытые строки действительно совсем не обязательно, просто я привык сохранять всё. Причины? Возможно, скрытые строки всё-таки понадобятся. Или вы захотите точно знать, какие строки были проигнорированы (мой Perl-сценарий, как вы помните, сообщает о каждой скрытой строке). Кроме того, информация о высоте строк может быть критерием для идентификации заголовков... Хотя, конечно, вы можете слегка модифицировать VB-код и не сохранять скрытые строки.
По скрипту на Perl Конечно, весь HTML-код (а это большая часть скрипта) вы скорее всего значительно измените. Конечно, вам придётся изменить количество столбцов, шапку, многие удалят из HTML-кода мои пустые строчки-разделители, накрутят вложенных таблиц, изменят DHTML-функции, добавят CSS-таблицы... Но это не самое главное и не принципиальное изменение.
82
Скорее всего вам придётся «научить» этот сценарий разбивать большие документы на разделы и сохранять эти разделы в разных файлах, потому что прайс-лист весьма средней фирмы в формате HTML может потянуть на сотни килобайт. Не всякий веб-странник дождётся конца загрузки такого документа. Возможно, вы захотите добавить сортировку (если позиции в печатном прайс-листе и в веб-прайсе должны следовать в разном порядке). Несомненно, будет полезна функция сравнения текущего прайса с предыдущим, которая будет добавлять информацию об обновлениях и динамике цен. Я бы советовал организовать подобные процедуры (не относящиеся непосредственно к HTML-вёрстке) в виде отдельных программ или модулей. Кстати, часть работы по HTML-вёрстке можно доверить механизму SSI, а скрипт пусть собирает SHTML-документ. Набор простых инструментов всегда удобнее, гибче и управляемее, чем один универсальный. Держитесь подальше от грабель, по которым гуляют создатели телефона-микроволновки и телевизора-зубной щётки. Список советов и предложений можно продолжать бесконечно, но я думаю, что уже разбудил вашу фантазию, и дальше вы справитесь и без меня. Адаптация приведённого здесь примера к вашим конкретным условиям, возможно, потребует несколько часов работы. Зато потом вы будете щедро вознаграждены, ведь все последующие обновления информации на вашем веб-сервере вы будете делать буквально в несколько касаний клавиатуры и мыши!
образование
СЕРГЕЙ ЯРЕМЧУК
84
образование Сейчас во многих школах, институтах и других учебных заведениях можно встретить компьютеры старого парка, уже отслужившие свое как морально, так и физически. На таких компьютерах можно изучать разве что Dos, что далеко от реалий сегодняшнего дня. К тому же у большинства, как правило, жесткий диск уже в нерабочем состоянии. Но и выбросить жалко, а новых никто не дает. Различные спонсоры, меценаты, бывает, подарят компьютер (один) и радуются, как дети. Спасибо, конечно, большое, но проблемы, как вы понимаете, этот компьютер в общем не решает, даже наоборот, усугубляет, работать на старых уже как-то не хочется, теперь просто есть с чем сравнивать. Но выход из такой ситуации есть. И мне кажется, что даже почти идеальный, но сначала суть. Все ОС Unix и подобные операционные системы изначально отлично подготовлены для полноценной работы в среде клиент-сервер. Даже X-Window не удалось избежать данной участи. Это сетевой продукт, одна часть которого (сервер) взаимодействует непосредственно с пользователем с помощью клавиатуры, мыши и монитора, она обрабатывает команды пользователя и формирует соответствующие запросы на их выполнение. Результаты работы программ передаются также непосредственно ему. А другая (клиент) уже обрабатывает результаты запросов и запускает запрошенные программы, а затем передает результат выполнения обратно серверу. Основой взаимодействия графических приложений с сервером является протокол Х, который реализован так, что ему абсолютно не важно, где находится клиент и сервер. В самом общем случае они работают на одном компьютере, но ничто, повторяю, ничто не мешает разместить их на разных компьютерах, ну разве что отсутствие какой-либо связи между ними. Такая организация позволяет эффективно использовать компьютерный парк организации: все ресурсоемкие операции выполняются на специально выделенном мощном компьютере. То есть имеется несколько более слабых компьютеров, за которыми работают пользователи. Такие компьютеры используют Unix с установленным сервером X-Window. Операционная система обрабатывает запросы, создаваемые пользователем, и передает его серверу, который в свою очередь возвращает результат. Эти компьютеры принято называть Х-терминалами. А компьютер, выполняющий основную наиболее трудоемкую работу, называют сервером графических приложений. Конечно же, к ресурсам такого компьютера предьявляются особые требования, особенно это относится к объему оперативной памяти, которой должно теперь хватать на всех, и к скорости дисковых операций. А вот к рабочим станциям пользователя требования уже гораздо ниже. С возлагаемой на них задачей спокойно могут справиться и «четверки». Но и это еще не все. При подключении к серверу жесткий диск становится не у дел. Все необходимые для обработки данные находятся на сервере. Терминал в таком случае использует локальный жесткий диск фактически лишь для загрузки системы. Неужели в таком случае нельзя обойтись как-нибудь без него?
№12(13), декабрь 2003
Оказывается, можно. Открытость Linux-систем породила вокруг себя довольно много полезных проектов, и часто для решения какой-нибудь проблемы необходимо просто найти подходящий. Решением вопроса загрузки бездисковых терминалов занимается LTSP (Linux Terminal Server Project). В чем же преимущество компьютера без диска: Подвижность пользователя, ведь как уже отмечалось, пользователь не связан с конкретным компьютером. Снижение стоимости и упрощение операции обновления программного обеспечения, так как это производится только на одном компьютере. Резервирование, восстановление данных будет происходить также только на одном компьютере. Физическая защита данных лучше, так как единственное, что необходимо защищать – сервер, а его можно поставить в специальном хорошо охраняемом помещении (которое, кстати, можно оборудовать фильтрами от проникновения пыли и аппаратурой для поддержания постоянной температуры, что существенно продлит срок работы сервера). UPS можно предоставить только серверу. Также будет существенно ниже общая цена – экономия = (стоимость жесткого диска + стоимость CD-ROM + стоимость флоппи-дисковода) ∗ количество компьтеров. Защищать от вирусов необходимо только сервер, так как другие компьютеры не имеют жесткого диска. Уровень шума на рабочем месте ниже, так как в компьютере нет частей, которые движутся – практически нет необходимости в администрировании и обслуживании в клиентских компьютерах. Большая долговечность клиентских машин как моральная, так и физическая. Возможность работы в запыленных помещениях (здесь желателен «холодный» процессор типа VIA C3, ЖК монитор). Как видите, подобное решение может быть использовано и в офисах и прочих местах, где нет необходимости держать мощные компьютеры. Вот мы подошли, наконец, к практическому решению поставленной в начале статьи задачи. Чтобы разобраться в дальнейших действиях, необходимо немного понимать общую картину. Поэтому сначала давайте проследим, как же все это происходит. Загрузка бездисковых станций происходит следующим образом. После включения питания управление передается, как обычно BIOS, который в свою очередь выполняет инициализацию, проверку POST (Power-On-Self-Test) и анализирует порты на наличие дополнительных устройств. В ходе последней обнаруживается установленная сетевая карта, в энергонезависимой памяти которой обнаруживается код, начинающий выполняться после завершения теста. Дальнейшую работу условно можно разделить на три этапа: получение IP-адреса, получение образа операционной системы и собственно работа с данными. Чтобы получить IP-адреса, программа загрузки инициализиру-
85
образование ет широковещательный запрос (для нашего примера 192.168.0.255, по умолчанию используется порт 68, протокол UDP), в котором указывается свой уникальный для каждой сетевой карты МАС-адрес. Для динамического распределения IP-адреса между компьютерами в сети используется служба DHCP. DHCP-сервер, приняв запрос, находит конфигурацию, соответствующую данному МАС-адресу, и возвращает cледующие данные: IP-адрес рабочей станции. Маску сети. Путь к загружаемому ядру ОС. Путь к каталогу, который монтируется в качестве корневого. Переговоры между клиентом и сервером можно воспроизвести примерно так. Клиент: «Привет, мой аппаратный адрес 00-02-44-07FC-C4, дай мне мой IP-адрес». Сервер: «(Ищет адрес в базе данных.) Ваше имя – aldebaran, ваш IP-адрес – 192.168.0.100, ваш сервер – 192.168.0.1, файл, от которого вы загружаетесь, находится в /tftpboot/ltsp/vmlinuz-2.4.21-ltsp-1 и остальная информация). Естественно, в сети должен находиться один такой сервер, иначе они передерутся между собой, и, конечно же, необязательно он должен быть нашим сервером графических приложений. После получения адреса клиент должен загрузить ядро операционной системы. Для этого используется протокол TFTP (тривиальный протокол передачи файлов). Это просто облегченная версия протокола FTP, которая не требует идентификации и использует UDP-протокол вместо TCP. Ну а чтобы пользоваться файловой системой, на другом компьютере на сервере должна быть настроена служба NFS. После загрузки ядра оно, уже как и положено, берет бразды правления в свои руки. Вот вкратце и все. Теперь займемся практической реализацией. Для того чтобы было возможным загружаться описанным выше способом, необходимо записать образ загрузчика, поддерживающего определенную сетевую карту в EPROM (Erasable Programmable Read-Only Memory – перезаписываемая память). Для этого заходим на сайт http://rom-o-matic.net/ и в выпадающем списке «Choose NIC/ROM type» выбираем марку чипа на сетевой карте. Здесь я допустил ошибку, помня, что сетевая карта NE2000 совместимая, просто скачал образ для NE. И вполне естественно, при загрузке получил что-то вроде «не могу найти NE*-карту». Пришлось раскрывать корпус одного из компьютеров и смотреть, что там такое установлено, заодно и сам узнал марку чипа – rtl8029. В меню «Choose ROM output format» выберите интересующий формат. Доступны следующие варианты образов: Floppy Bootable ROM Image (.lzdsk) – загрузчик с дискеты (на первом этапе лучше воспользоваться именно им). Binary ROM Image (.lzrom) – прошивка ПЗУ сетевой карты. LILO Bootable ROM (.lzlilo) – загрузка с использованием LILO.
86
DOS Executable ROM Image (.com) – DOS-загрузчик
тоже подходит, только уберите загрузку himem.sys и emm386.exe, а то работать, скорее всего, не будет, и добавьте соответствующие строки в файл config.sys для загрузки. PXE loadable ROM Image (.lzpxe) – то же, что и второй пункт, но разработки Intel.
Выбираем вариант Floppy Bootable ROM Image, при нажатии на кнопку «Get ROM» вы получаете нужный образ. Чтобы перезаписать его на дискету, воспользуйтесь программой rewrite под Windows, которая входит в состав практически каждого дистрибутива Linux, а в Linux дайте следующую команду: #cat your_image.lzdsk > /dev/fd0
или #dd if=/path/to/rom-image of=/dev/fd0 bs=1024
как кому привычнее. Программа первоначальной загрузки готова. Первоначально я советую попробовать загружаться с дискеты и настроить схему один сервер – один клиент, а после успешного преодоления всех подводных камней уже нарастить количество клиентов и заняться прошивкой кода в ПЗУ. Приступаем к наиболее веселому занятию – настройке сервера. Отправная точка в Интернете для поиска необходимой информации и программ – официальный сайт проекта http://www.ltsp.org. Конфигурация сервера Athlon 1.3 Гц, 256 Мб, 10 Mбит сетевая карта. Пять клиентов Pentium-100, 16 Мб, Video S3 Trio 3D 4 Мб. Все это настраивалось под операционными системами Linux Mandrake 8.0 и Red Hat 7.3. Для того чтобы это все работало на данных системах, были установлены следующие сервисы: dhcp, nfs, portmap, tftp (клиент и сервер), если понадобится telnet-сессия, то и telnet-сервер и запущена служба xinetd. На установке выше перечисленных сервисов я останавливаться не буду, хотя бы потому, что большинство их входит в состав соответствующих дистрибутивов, и если нет в стандартной поставке, то их всегда можно найти на соответствующем сайте. Для настройки ltsp нам понадобятся следующие пакеты, которые можно взять с http://prdownloads.sourceforge.net/ ltsp/, все они доступны как в виде перекомпилированных пакетов в формате rpm или deb, так и в виде исходников. Какие устанавливать – дело вкуса и опыта. Я скачал в формате tgz. Итак, какие необходимо скачать пакеты (версию не указываю специально, так как к моменту выхода статьи все может измениться, плюс уже давно ходит в бетах версия 4): ltsp_core – основной пакет, необходимый для работы; ltsp_kernel – ядро, загружаемое на клиентский компьютер; ltsp_x_core – пакет, необходимый для запуска XWindow версии 4.х на клиентском компьютере; ltsp_x_fonts – пакет со шрифтами (скачал по рекомендации на сайте, но вполне можно обойтись и без него).
образование Если видеокарта не поддерживается в версии 4.х, необходимо дополнительно выбрать пакет с версией сервера 3.3.6 применительно к видеокарте, установленной на ваших клиентских компьютерах (в моем случае это ltsp_x336_s3), или, если нет, то ltsp_x336_svga, но при этом не будут работать TrueType-шрифты и сглаживание. На сайте также доступны пакеты для поддержки звука, сканера, веб-камер и wireless-устройств на терминале, пакеты для организации Windows-терминала и еще много чего. Первым обязательно должен быть установлен пакет ltsp_core. Установка заключается в распаковке (tar xvzf) и запуске инсталляционного скрипта (cd ltsp_ххх, ./install.sh). Остальные устанавливаются аналогично. Для rpm-пакетов просто дайте команду: # rpm -ivh ltsp_core-3.0.9-0.i386.rpm
и аналогичную для остальных. При запуске скрипта установки ltsp_core выдается информация, которая подразумевается по умолчанию, все настройки можно изменить в файле config, желательно до начала инсталляции, а то потом придется править во всех файлах по отдельности: Good! We have found RedHat version 7.3 About to install LTSP, using the following settings: # êàòàëîã, â êîòîðûé óñòàíàâëèâàþòñÿ ïàêåòû LTSP_DIR = /opt/ltsp SWAP_DIR = /var/opt/ltsp/swapfiles # êàòàëîã äëÿ çàãðóæàåìîãî ÿäðà TFTP_DIR = /tftpboot # àäðåñ ñåòè IP_NETWORK = 192.168.0.0 # àäðåñ ñåðâåðà IP_SERVER = 192.168.0.1 # ìàñêà ñåòè IP_NETMASK = 255.255.255.0 # øèðîêîâåùàòåëüíûé àäðåñ ñåòè IP_BROADCAST = 192.168.0.255
После установки всех пакетов перейдите в каталог /opt/ ltsp/templates/ и запустите скрипт ./ltsp_initialize, который внесет необходимые изменения в конфигурационные файлы вышеперечисленных сервисов. Внимательно читайте выходные данные, если что-то у вас не установлено, то скрипт выдаст сообщение об ошибке. Теперь давайте перейдем к ручной доводке сервисов. Сервис dhcp настраивается в файле /etc/dhcpd.conf, который при установке в большинстве дистрибутивов не создается, поэтому первоначально может потребоваться его создать: #touch /etc/dhcpd.conf
Для того чтобы правильно его настроить, необходимо знать MAC-адрес сетевой карты, IP-адрес сервера и сетевую маску. Для выяснения MAC-адреса я нашел в Интернете множество программ, написал одну на Perl, воспользовавшись модулем с CPAN, затем вспомнил, что демон arpd сохраняет информацию о всех MAC-адресах и их IP-адресах в пределах локальной сети, а проблема решилась проще, чем я думал, при запуске образа, который мы приготовили на дискете раньше, выдается требуемый MAC-адрес сетевой карты, установленной на компьютере.
№12(13), декабрь 2003
Для начала о некоторых допущениях, связанных с конфигурацией локальной сети. В сети 192.168.0.0/255.255.255.0 для бездисковых терминалов выделены адреса с 192.168.0.100 по 192.168.0.254. Серверы DHCP и LTSP находятся на компьютере 192.168.0.1. Тогда файл /etc/ dhcpd.conf будет иметь такой вид: subnet 192.168.0.0 netmask 255.255.255.0 { range 192.168.0.2 192.168.0.100; option subnet-mask 255.255.255.0; option broadcast-address 192.168.0.255; option routers 192.168.0.1; option domain-name-servers 192.168.0.1; option domain-name "server.org"; option log-servers 192.168.0.1; host term1 { hardware ethernet 00-02-44-07-FC-C4; fixed-address 192.168.0.100; option host-name "term1"; option root-path "192.168.0.1:/opt/ltsp/i386"; filename "lts/vmlinuz-2.4.21-ltsp-1"; }
Небольшое пояснение. В начале конфигурационного файла расположены инструкции, относящиеся ко всем компьютерам сети. Их смысл очевиден. Поскольку на терминалах нет жесткого диска, то демону журналирования syslogd в строке option log-servers 192.168.0.1 указывается удаленный сервер, который будет записывать от него сообщения. Для того чтобы демон syslogd на сервере мог принимать сообщения от терминалов, в файле конфигурации /etc/sysconfig/syslog, должен использоваться ключ -r: # Options to syslogd # -m 0 disables 'MARK' messages. # -r enables logging from remote machines # -x disables DNS lookups on messages recieved with -r # See syslogd(8) for more details SYSLOGD_OPTIONS="-m 0 -r "
Далее идут индивидуальные настройки для каждого компьютера клиента. Здесь можно переопределить настройки сервера индивидуально. В строке hardware ethernet 00-02-44-07-FC-C4 указывается аппаратный МАС-адрес сетевой карты, а в строке fixed-address 192.168.0.100 за ним статически закрепляется IP-адрес. Теперь при запросе клиента с указанным МАС-адресом ему всегда будет выдаваться IP-адрес 192.168.0.100. Остальным же он будет назначаться на общих правилах, из таблицы свободных адресов. Строка option rootpath указывает на раздел, который будет смонтирован в качестве корневого с помощью службы NFS, его можно прописать и в глобальной секции, но только в том случае, если в данной сети используются только бездисковые станции, иначе ноутбук шефа будет загружать что попало. Для того чтобы данный ресурс был виден в сети, необходимо в файле /etc/exports сервера LTSP указать каталоги, доступные для сетевого монтирования: /opt/ltsp/i386 192.168.0.0/255.255.255.0 (ro, no_root_squash) /var/opt/ltsp/swapfiles (rw, no_root_squash)
Слева указаны каталоги, которые экспортирует сервер, первая строка – корневую систему, а вторая – раздел свопирования, если в нем есть необходимость. Справа указаны опции. Флаги ro и rw указывают на доступ толь-
87
образование ко для чтения и для записи и чтения соответственно. А no_root_squash заменяет пользователя root более безобидным nobody. Параметры ro и no_root_squash, используются в файле по умолчанию, и поэтому их можно смело опустить, но так как-то нагляднее. Ядро может автоматически определить только PCI сетевую карту, если у вас ISA, то добавьте следующие строки для каждого описываемого клиента. option option-128 option option-129
service tftp { socket_type protocol wait user server server_args disable per_source cps }
e4:45:74:68:00:00; "NIC=ne IO=0x300";
Здесь хочется отметить, что «option-128» в этом случае не является mac-адресом, это специальный ключ для загрузки Etherboot. Параметр «option-129» указывает ядру, какой именно драйвер сетевой карты необходимо загружать. Параметр filename указывает путь к ядру, который необходимо загружать. Пакет LTSP поставляется с двумя ядрами, поддерживающими большинство сетевых карт: одно описано выше, а второе с префиксом lpp (Linux Progress Patch) в имени. При использовании последнего ядра на компьютере клиента при загрузке отображается статус-бар, данное ядро рекомендуется использовать, после того как удалось все настроить и загрузиться с обычного. Дополнительно может понадобиться для экспорта домашних каталогов пользователей /home добавить следующие строки в файл /etc/exports: /home
вы полностью доверяете всем компьютерам, а от внешних собратьев закрыться firewall. Файл /etc/xinet.d/tftp будет иметь такой вид:
192.168.0.0/255.255.255.0
(rw)
а в файл /opt/ltsp/i386/etc/fstab: ltsp-server:/home/ /home nfs defaults,rsize=8192,wsize=8192 0 0
= = = = = = = = =
dgram udp yes root /usr/sbin/in.tftpd -s /tftpboot no 11 100 2
На этом настройки данных серверов можно считать законченными. Желательно проверить их работу перед применением. [root@grinder root]# tftp grinder tftp> get lts/vmlinuz-2.4.21-ltsp-1 Received 1062469 bytes in 0.9 seconds tftp> quit
Имя файла указано так потому, что корневой каталог для этого сервиса определен в файле /etc/xinet.d/tftp как server_args= -s /tftpboot, т.е. каталог /tftpboot делается корневым (chroot), и поэтому если указать полный путь, то сервер просто не найдет необходимый файл. Меньше всего возни с настройкой сервера шрифтов было в дистрибутиве Red Hat. А с настройкой в остальных мне очень помог разобраться документ http:// www.ltsp.org/contrib/AbiWordfont.txt. В файле /etc/X11/fs/ config в строке «client-limit = 10» установите число компьютеров клиентов, рекомендуемое не более сорока. В файле /etc/X11/XF86Config (или XF86Config-4, если вы используете четвертую версию сервера) замените строку:
И обязательно добавьте в файл /etc/hosts описание компьютеров сервера и клиентов для нормальной работы службы NFS. Например:
FontPath
"unix/:-1"
FontPath
"tcp/localhost:7100"
на /etc/hosts 127.0.0.1 localhost.localdomain localhost … 192.168.0.1 server.org 192.168.0.100 term1
А в файле /etc/rc.d/init.d/xfs замените строку:
Теперь необходимо перезапустить сервис dhcpd: daemon --check xfs xfs -port -1 -daemon -droppriv -user xfs [root@grinder etc]# /etc/init.d/dhcpd restart Îñòàíàâëèâàåòñÿ dhcpd: [ ÑÁÎÉ ] Çàïóñêàåòñÿ dhcpd: [ ÎÊ ] [root@grinder etc]# /etc/init.d/dhcpd status dhcpd (pid 979) âûïîëíÿåòñÿ...
На этом настройку dhcpd можно считать законченной. Теперь о настройках остальных сервисов. Общим для некоторых из них является то, что если сервис запускается с помощью xinetd (tftp, telnet), то он обязательно должен быть разрешен (в файлах /etc/xinet.d/tftp и /etc/xinet.d/ telnet), для этого требуется заменить disable = yes на disable = no. Также в целях улучшения безопасности могут быть определены IP-адреса, с которых разрешен доступ к данному сервису (по умолчанию localhost), т.е. в нашем случае only_from = 192.168.0.0. Кстати, вообще вышеописанное желательно проводить в сетях, в которых
88
на daemon --check xfs xfs -port 7100 -daemon -droppriv -user xfs
и строку: daemon --check xfs su xfs -c \"xfs -port -1\" -s /bin/sh
на daemon --check xfs su xfs -c \"xfs -port 7100\" -s /bin/sh
Перезапустите сервер и проверьте, слушает ли он порт под номером 7100. Для того чтобы терминалы могли зап-
образование рашивать у сервера сеанс XDM, требуемый для регистрации пользователя и запуска пользовательской сессии, необходимый при использовании X-Window, требуется в конфигурационном файле /etc/X11/xdm/xdm-config на сервере LTSP внести соответствующие изменения: ! SECURITY: do not listen for XDMCP or Chooser requests ! Comment out this line if you want to manage X terminals with xdm # ýòîò ïóíêò îáÿçàòåëüíî çàêîììåíòèðîâàòü ! DisplayManager.requestPort: 0 # Ýòó ñòðî÷êó äîáàâèòü, ïðàâäà íåîáÿçàòåëüíî. Îñòàëüíûå # ìîæíî íå òðîãàòü. DisplayManager.*.setup:/etc/X11/xdm/Xsetup_workstation Ñêðèïò Xsetup_workstation èìååò òàêîé âèä: #! /bin/sh /usr/X11R6/bin/xsetroot -solid "#356390" if [- x /usr/bin/xsri]; then /usr/bin/xsri -geometry +5 +5 -avoid 300x250 ↵ -keepaspect /etc/X11/xdm/ltsp.gif fi
И остался «последний и решительный бой». Правка самого главного конфигурационного файла LTSP /opt/ ltsp/i386/etc/lts.conf. Наиболее подробную информацию о настройках тех или иных параметров можно узнать из файла /opt/ltsp/i386/etc/lts.conf.readme. Данный файл состоит из раздела [Default], в котором определяются общие для всех клиентов параметры, и разделов, определяющих индивидуальные для каждого клиента, в них при необходимости можно переопределить те или иные глобальные установки. Благодаря такой схеме появляется возможность более гибкой адаптации к аппаратной конфигурации терминалов. Итак, пример файла lts.conf: [Default] SERVER = 192.168.0.1 # êîìïüþòåð, âûñòóïàþùèé â ðîëè ñåðâåðà ãðàôè÷åñêèõ ïðèëîæåíèé XSERVER = auto # óêàçûâàåò íà òî, ÷òî ñèñòåìà ñàìà îïðåäåëÿåò òèï çàãðóæàåìîãî # XFree86-ñåðâåðà X_MOUSE_PROTOCOL = "IMPS/2" # íàçâàíèå ïðîòîêîëà ìàíèïóëÿòîðà ìûøè # â äàííîì ñëó÷àå èñïîëüçóåòñÿ ìûøü ñî ñêðîëëèíãîì, åñëè # îáûêíîâåííàÿ ìûøü ïîäêëþ÷àåìàÿ ê ïîðòó PS/2, òî ïîïðîáóéòå # ïðîñòî PS/2 X_MOUSE_DEVICE = "/dev/psaux" # óêàçûâàåò íà ïîðò PS/2 X_MOUSE_RESOLUTION = 50 X_MOUSE_BUTTONS = 3 LOCAL_APPS = N USE_XFS = Y # èñïîëüçóåòñÿ ñåòåâîé ñåðâåð øðèôòîâ RUNLEVEL = 5 SOUND = Y VOLUME = 75
И секция для клиента. В качестве ее названия может выступать имя хоста, МАС- или IP-адрес, т.е. [term1], [192.168.0.100] или [00-02-44-07-FC-C4]. [term1] # # # # # # # #
XSERVER = XF86_SVGA Òèï X-ñåðâåðà, êîòîðûé áóäåò âûïîëíÿòüñÿ íà êëèåíòñêîé ñòàíöèè. Äëÿ ÷åòâåðòîé âåðñèè óêàçûâàåòñÿ âèäåîìîäóëü, íàïðèìåð nv. Äëÿ XFree86 3.3.6 óêàçûâàåòñÿ èìÿ ñåðâåðà XF86_SVGA, XF86_S3 è ò.ä. X_MODE_0 = 800x600 40 800 840 968 1056 600 601 605 628 ↵ +hsync +vsync óñòàíîâêà ïàðàìåòðîâ âûâîäà íà ýêðàí, èõ ìîæåò áûòü íåñêîëüêî îò X_MODE_0 äî X_MODE_10 X_VIDEORAM = 4096 # êîëè÷åñòâî âèäåîïàìÿòè X_MOUSE_PROTOCOL = "Microsoft" ìûøü ñ ïîñëåäîâàòåëüíûì èíòåðôåéñîì X_MOUSE_DEVICE = "/dev/ttyS0" ìûøü, ïîäêëþ÷àåìàÿ ê ïàðàëëåëüíîìó ïîðòó X_MOUSE_RESOLUTION = 50
№12(13), декабрь 2003
X_MOUSE_BUTTONS = 2 # êîëè÷åñòâî êíîïîê ìûøè # âêëþ÷åíèå ýìóëÿöèè òðåòüåé êíîïêè ìûøè # (íàæàòèåì äâóõ èìåþùèõñÿ îäíîâðåìåííî) X_MOUSE_EMULATE3BTN = Y X_MOUSE_BAUD = 1200 RUNLEVEL = 3
Уровень инициализации (RUNLEVEL) 3 загружает командную строку bash_shell в консоли, этот параметр желательно установить первым для отладки работы сервисов, и если все получилось, то использовать либо 4 для telnet-сессии, позволяющей открывать несколько терминалов на сервере и переключаться между ними по Alt-F1 до Alt-F9, либо 5 для автоматического старта X-Windows. Для каждого клиента, как видите, есть возможность определить индивидуальные параметры Х-сервера в секции, но возможен и другой вариант, он особенно удобен, если имеется несколько клиентов с одинаковыми видеокартами. Для этого необходимо указать в параметре XF86CONFIG_FILE = XF86Config.term1 имя конфигурационного файла для данного клиента и поместить его в каталог /opt/ltsp/i386/etc/X11/ (предварительно создав каталог Х11). Мне в этом смысле немного повезло, на одном из клиентских компьютеров до этого стоял Linux, поэтому генерировать данный файл заново не пришлось. Если у вас другая ситуация, то попробуйте использовать программу /usr/X11R6/bin/xf86config на сервере, установив туда нужную видеокарту (не забудьте сохранить при этом оригинальные файлы). Дополнительно можно переопределить параметры клавиатуры, используемые по умолчанию. Для этого предназначены следующие опции: XkbModel – модель клавиатуры, наиболее распространенные – pc 101, pc 102, pc 105; XkbLayout – раскладка клавиатуры, например us (по умолчанию), ru, ru(winkeys); XkbSymbols – таблица скан-кодов, по умолчанию «us(pc 101)», но можно заменить, например на «us(pc105) + ru». Раз уже коснулись раскладки клавиатуры, то два слова о том, как использовать русскую. Для установки и переключения на русский вариант (в рассматриваемом случае) раскладки клавиатуры в XFree86 применяется два параметра XkbLayout и XkbOptions. Первый, как уже отмечалось, можно переопределить, а вот для того чтобы была возможность переключаться между раскладками, необходимо выполнить еще некоторые действия. Все настройки, касающиеся параметров XFree86 во всех Linux производятся в файле XF86Config для версии 3 и в XF86Config-4 для четвертой версии. Но для терминалов таких файлов изначально не существует, они генерируются динамически при запуске. Для этих целей используется скрипт /opt/ltsp/i386/etc/rc.setupx3 для клиентов с версией 3 и /opt/ltsp/i386/etc/rc.setupx для четвертой версии, которые, кстати, берут основные параметры для настройки из файла lts.conf. Так вот, для того чтобы переключатель заработал, необходимо после строки XkbLayout «${XkbLayout}» для rc.setupx3 или Option «XkbLayout» «${XkbLayout:-»us»}» для rc.setupx прописать параметр,
89
образование устанавливающий комбинацию для изменения раскладки, например: XkbOptions «grp:caps_toggle» – переключение по Caps Lock; XkbOptions «grp:alt_shift_toggle» – более привычное для пользователей Windows переключение по Alt + Shift. Вот и все. Самое интересное, что это действительно работает. На клиентском компьютере загрузить даже KDE с OpenOffice и причем с вполне терпимой скоростью, после перехода на оконный менеджер IceWM и запуска аналога OpenWritera от GnomeOffice – AbiWord система вообще летала. Конечно, при увеличении количества клиентов до 10 желателен сервер помощнее, как минимум оперативной памяти 512 Мб. Наиболее очевидное применение данной технологии – это наши учебные заведения со старыми компьютерными классами, где добавление одного мощного компьютера позволит работать с современным ПО. В организации интернет-кафе с помощью технологии LTSP поможет скрипт: http:// prdownloads.sourceforge.net/ltsp/ltsp_phpSiCafe-0.0.1.tgz, назначение которого – учет времени, проведенного пользователями за компьютером. Заинтересовавшимся советую также заглянуть еще на два сайта. Первый http://k12ltsp.org/, этот проект предназначен для установки терминального сервера, разработанного для школ, базируется на дистрибутиве Red Hat. Второй http:// www.ltsp.ru/, как видно из названия, русский сайт проекта. Здесь уже можно найти переводную документацию по работе с бездисковыми станциями, описание установки виртуальной машины VMWare для запуска приложений, написанных под Windows. Все это, конечно, интересно и работает уже более года, но совсем недавно познакомившись с проектом OpenMosix (http://openmosix.sourceforge.net/), предлагающим OpenSource-решение создания кластерных систем на основе компьютеров, соединенных в единую сеть. OpenMosix представляет собой расширение к обычному ядру Linux, при его установке узлы в кластере начинают «общаться» с друг другом, и кластер адаптирует себя к рабочей нагрузке. Процессы, обрабатывающиеся на любом из узлов, при увеличении нагрузки данного компьютера по сравнению с другими способны передаваться на любой другой компьютер кластера. OpenMosix постоянно пытается оптимизировать распределение ресурса между машинами, при этом новый узел может быть добавлен «на лету» и автоматически будет подхвачен кластером. Так как все openMosix расширения выполняются внутри ядра, каждое из приложений, автоматически извлекает выгоду из распределенной вычислительной концепции openMosix. Кластер ведет себя фактически как многопроцессорная система, правда без ограничения на их максимальное число. И естественно возникло желание испытать это все в деле, тем более что большая часть работы уже проделана. Как и в приведенном выше примере, один из компьютеров играет роль главного (master), а остальные, сколько есть, подчиненные (slave). Для работы понадобятся сами ядра с патчем от openMosix и инструменты
90
для работы openmosix-tools. Все это можно найти на странице http://prdownloads.sourceforge.net/openmosix/, где доступны как сами патчи, так и уже перекомпилированые (серверные) ядра для разных платформ, причем уже доступны патчи для ядер серии 2.6. Мы будем устанавливать при помощи патча, самостоятельно компилируя все ядра. Для этого берем ядро 2.4.22: # wget -c http://www.kernel.org/pub/linux/kernel/v2.4/ ↵ linux-2.4.22.tar.bz2 # wget -c http://tab.tuxfamily.org/download/openmosix/ ↵ patch-2.4.22-om-20030811.bz2
Теперь все разархивируем: # # # #
tar -xjvf - linux-2.4.22.tar.bz2 cd linux-2.4.22 bzcat ../patch-2.4.22-om-20030825.bz2|patch -p1 ln -sf /path/to/linux-2.4.22 /usr/src/linux
Теперь заходим в него: # cd /usr/src/linux
Конфигурируем серверное ядро: # make xconfig {menuconfig, gconfig}
И смотрим, чтобы следующие пункты были включены в ядро, а не в виде модулей: openMosix --openMosix process migration support openMosix File-System Networking options --Packet Socket Socket Filtering TCP/IP networking IP: multicasting File systems --/proc file system support Network File Systems --NFS file system support NFS server support Provide NFSv3 server support
И компилируем новое ядро: # make dep # make bzImage && make modules && make modules_install
Для ядер серии 2.6 достаточно ввести make all. Копируем ядро на свое место: # mv arch/i386/boot/bzImage /boot/vmlinuz-openmosix
Конфигурируем загрузчик для работы с новым ядром, и после перезагрузки система будет готова. Если установка производится при помощи перекомпилированных пакетов, все вышеописанное (кроме настройки загрузчика) будет в систему добавленно автоматически. Для этого вводим: # rpm -ivh openmosix-kernel-2.4.22-openmosix1.i686.rpm
образование Установка slave-ядра Для начала сохраняем конфигурационный файл основного ядра. # cp /usr/src/linux/.config /usr/src/linux/.config_master
Само slave-ядро лучше собирать без поддержки модулей, т.к. настройка их загрузки через сеть – довольно хлопотное дело, также желательно побеспокоиться о компактности, отключив как можно больше ненужных функций. Следующие опции нужно включить в ядро. openMosix --openMosix process migration support openMosix File-System Networking options --TCP/IP networking IP: kernel level auto-configuration IP: DHCP support IP: BOOTP support File systems --/proc file system support Network File Systems --NFS file system support Provide NFSv3 client support Root file system on NFS
Но получившееся в результате ядро копируем в другое место, а именно в каталог /tftpboot. Например:
которые будут задействованы в кластере. Каждая строка в этом файле состоит из трех частей: 1 2
192.168.0.1 1 192.168.0.100 10
Первым идет openMosix node-number узла в указанном диапазоне, второй строкой – IP-адрес или имя, описанное в файле /etc/hosts, и третьей – количество узлов в этом диапазоне. В данном примере нашему серверу присвоен openMosix node-number 1, а десяти узлам в диапазоне 192.168.0.100-192.168.0.109, номера 2-11. Если бы IP-адреса шли подряд, то можно было бы обойтись и одной строкой. После правки файла делаем его доступным и другим узлам. # cp /etc/openmosix.map /opt/ltsp/i386/etc/
Туда же копируем и бинарные файлы openmosix-tools. # # # # # #
cp /sbin/setpe /opt/ltsp/i386/sbin/ cp /bin/mosrun /opt/ltsp/i386/bin/ cp /bin/mosmon /opt/ltsp/i386/bin/ cp /bin/mosctl /opt/ltsp/i386/bin/ cp /bin/migrate /opt/ltsp/i386/bin/ cp /etc/rc.d/init.d/openmosix /opt/ltsp/i386/etc/rc.openmosix
И запускаем openМosix: # /etc/init.d/openmosix start
# cp /usr/src/linux/arch/i386/boot/bzImage ↵ /tftpboot/lts/vmlinuz-openmosix-slave
И настраиваем его загрузку описанным выше способом. В принципе для этого не обязательно иметь установленный полный пакет ltsp, а все необходимое создать вручную, как это все сделать, можно найти в дополнительной литературе, указаной в конце статьи. Но все равно, для того чтобы избежать большого количества ручной работы, советую в таком случае скачать файл ltsp_initrd_kit и ltsp_util_src (http://prdownloads.sourceforge.net/ltsp/ltsp_initrd_kit-3.0.11i386.tgz и http://prdownloads.sourceforge.net/ltsp/ltsp_util_src3.0.0-i386.tgz). Все, что мы делали до сих пор, фактически не отличается от предыдущего варианта ядра. Чтобы заставить компьютеры работать в одной связке и обмениваться нагрузкой, необходимо установить пакет openmosix-tools. Его также можно получить уже в виде перекомпилированных пакетов или все это проделать самому. Ничего особенного в компиляции нет: # ./configure –with-kerneldir=/usr/src/linux
Флагом -with-kerneldir указываем путь к исходным файлам ядра, по умолчанию /usr/src/linux-openmosix: # make && make install
Или строим пакет для rpm-based дистрибутивов: # rpmbuild -ta openmosix-tools-0.3.4.tar.gz
После окончания установки приступаем к настройке. Для начала в файле /etc/openmosix.map, определим узлы,
№12(13), декабрь 2003
После перезагрузки slave-узлов работу можно проконтролировать при помощи утилиты mosctl, введя номер нужного: # mosctl status 2
А в файле /etc/inittab рекомендуется строку: si::sysinit:/etc/rc.d/rc.sysinit
заменить на: si::sysinit:/bin/mosrun -h /etc/rc.d/rc.sysinit
Чтобы избежать проблем при использовании сервиса SSH в файле /etc/rc.d/init.d/sshd в функции start(), добавьте следующую линию: test -f /proc/$$/lock && echo 0 > /proc/$$/lock
Вот и все. Остается пожелать успехов, и я надеюсь, эта статья кому-то поможет. Кроме документации на сайтах проектов LTSP и openMosix советую просмотреть еще и следующие документы: 1. Колисниченко Д. Загрузка по сети. – //журнал «Системный администратор», №9(10), 2003 г. – 47-49 с. 2. LTSP + openMosix: Integration How-To: http://home.onestop.net/jjensen/ltsp-om5r3c.html 3. openMosix and Diskless Nodes: http://www.gentoo.org/doc/en/openmosix-howto.xml
91
cодержание журнала за 2003 год
Содержание журнала
АДМИНИСТРИРОВАНИЕ FreeBSD. Компиляция Александр Прокошев Ipfw и управление трафиком в FreeBSD Игорь Чубин IPSec через NAT: проблемы и решения Татьяна Антипова IRC-сервер Александр Слободской Milter = Mail + Filter Роман Сузи NetBSD: установка и настройка Андрей Бешков OpenBSD. Первые шаги Денис Назаров Postfix+...+SpamAssassin. Mini-howto Андрей Мозговой Python в администрировании сервера: почему бы и нет? Роман Сузи RADIUS Всеволод Стахов SMTP AUTN in da Postfix + ... Андрей Мозговой TACACS Всеволод Стахов Windows Server 2003: взгляд системного администратора Алексей Доля, Михаил Мельников Абсолютно все о ATM Сергей Ропчан Абсолютно все о Frame Relay Сергей Ропчан Абсолютно все о Х.25 Сергей Ропчан Абсолютно все о технологии ISDN Сергей Ропчан Архитектура файловой системы ext2 Владимир Мешков Аудит учетных записей пользователей в Active Directory Максим Костышин Борьба за системные ресурсы Денис Колисниченко Введение в OpenBSD Денис Назаров Виртуальный компьютер Денис Колисниченко Виртуальный полигон для администратора и разработчика Андрей Бешков Виртуальный полигон для разработчика и администратора на основе Linux и VMWare Андрей Бешков Восстановление данных с лазерных дисков Крис Касперски Восстановление загрузки операционной системы Linux Андрей Шевченко Дистанционное управление в Linux Денис Колисниченко Загрузка по сети Денис Колисниченко Империя Cisco Денис Еланский Интеграция SQUID + LDAP Марк Кричмар Искажение TOC как средство борьбы с несанкционированным копированием диска Крис Касперски Использование IPSec в Windows 200x Максим Костышин Использование LVM Сергей Яремчук Использование бездисковых маршрутизаторов Андрей Мозговой Как бороться с баннерами в ICQ Дмитрий Репин Как выключить ESMTP-команды в Exchange 2000 Server Татьяна Антипова Как пингвин говорит по телефону, или Настройка dialin-сервера для доступа Интернет и аварийной консоли Андрей Мозговой Контроль последовательных портов в Linux Денис Колисниченко Конфигурирование DHCP Денис Колисниченко Крепость для пингвина Сергей Яремчук Маленький Linux в качестве firewall Сергей Яремчук Мечта сисадмина Сергей Яремчук Миграция с Windows на Linux Дмитрий Галышев Мифы и легенды современной ОCологии… или «ОС – это большой полосатый мух?» Александр Потемкин Мониторинг Windows-серверов с помощью Nagios. Часть 1 Андрей Бешков Мониторинг Windows-серверов с помощью Nagios. Часть 2 Андрей Бешков Настраиваем ASPLinux 7.3 Server Edition Александр Шибенко Настройка Incoming Connection в Linux Сергей Ропчан Настройка сервера SSH Денис Колисниченко Новые средства OC FreeBSD 5 Всеволод Стахов Организация доступа в Интернет на предприятиях Алексей Федоров Осваиваем Nagios Андрей Бешков Пингвин с одного пинка Сергей Яремчук
92
№ №4(5) №6(7) №3(4) №7(8) №2(3) №8(9) №8(9) №9(10) №1 №4(5) №10(11) №3(4) №11(12) №4(5) №3(4) №1(2) №2(3) №11(12) №11(12) №4(5) №6(7) №6(7) №9(10) №11(12) №8(9) №2(3) №5(6) №9(10) №2(3) №11(12) №9(10) №6(7) №10(11) №11(12) №10(11) №3(4) №2(3) №7(8) №5(6) №12(13) №9(10) №10(11) №1 №2(3) №7(8) №8(9) №10(11) №4(5) №7(8) №8(9) №5(6) №12(13) №8(9)
Построение программных RAID-массивов в Linux Дмитрий Рожков Почтовая система для среднего и малого офиса Андрей Бешков Практика OpenSSL Всеволод Стахов Процессы и нити Всеволод Стахов Разводной мост на Linux (Bridging Firewalls) Павел Закляков Решение задач инвентаризации в сети Иван Коробко Свой собственный модуль Денис Колисниченко Система фильтрации интернет-трафика Андрей Бешков Скрипты для подсчета трафика: пример реализации в FreeBSD Денис Пеплин Создаем VPN на основе vtun Андрей Бешков Создание PDC (основного контроллера домена) для Windows на базе SAMBA 2.2.5 Андрей Гуселетов Создание загрузочных дискет и CD-дисков Linux Всеволод Стахов Создание простейшей биллинговой системы Денис Мясниченко Стартовые скрипты FreeBSD Денис Пеплин Статическая маршрутизация в Linux iproute2. Часть1 Всеволод Стахов Статическая маршрутизация в Linux iproute2. Часть2 Всеволод Стахов Теория и практика OpenSSL Всеволод Стахов Удаленное резервное копирование: пример реализации в FreeBSD Денис Пеплин Удобная почтовая система Вячеслав Калошин Управление сетевыми принтерами домена Иван Коробко Устанавливаем Multiple-Device-дозвон в Windows XP Татьяна Антипова Установка FreeBSD Сергей Яремчук Установка IMAP4-сервера на базе cyrus-imapd + sendmail Денис Шергин Установка Nagios Андрей Бешков Установка и настройка сервера Jabber на платформе Linux Сергей Индлин Учет работы Dialup-пользователей в системе FreeBSD Сергей Супрунов Учет трафика с помощью программ MRTG и LAN Billing Денис Колисниченко Файловые системы Linux Сергей Яремчук Хеви Хардвэр. Установка и настройка коммутаторов CISCO CATALYST серий 2900XL и 3500 Всеволод Стахов Что такое SAMBA? Сергей Яремчук Ы.Ы.Р. Особенности работы и настройки протокола SSH Всеволод Стахов Это должен знать каждый, или Четыре базовых принципа выбора коммутатора ЛВС Геннадий Карпов Эффективная почтовая система на базе Exim Денис Мысенко
№5(6) №5(6) №2(3) №5(6) №4(5) №12(13) №10(11) №4(5) №6(7) №4(5) №1(2) №6(7) №2(3) №7(8) №5(6) №6(7) №1(2) №5(6) №1 №10(11) №2(3) №3(4) №10(11) №2(3) №4(5) №12(13) №6(7) №11(12) №1 №1 №1(2) №5(6) №8(9)
СЕТИ
№
NETFILTER Владимир Мешков Powerline: Интернет из розетки Денис Колисниченко Анализатор сетевого трафика Владимир Мешков Дальняя связь. Как это бывает Денис Еланский Планируем переезд сети Вячеслав Калошин Программирование сокетов Всеволод Стахов Протокол V.90 Денис Колисниченко Сканер портов: пример реализации Владимир Мешков
№8(9) №7(8) №1 №6(7) №7(8) №1 №8(9) №1
БЕЗОПАСНОСТЬ
№
LIDS Сергей Яремчук OpenLDAP и защита данных Всеволод Стахов SELinux Сергей Яремчук Анализ защиты программ и рекомендации по ее усилению Станислав Гошко Атака на переполнение буфера через неисполнимый стек в Windows NT/2000/XP Станислав Гошко Безопасность технологии виртуальных карт Сергей Ропчан Борьба с вирусами: опыт контртеррористических операций Крис Касперски Защитим электронную почту! Всеволод Стахов
№4(5) №2(3) №5(6) №10(11) №9(10) №2(3) №10(11) №1(2)
содержание журнала за 2003 год
за 2003 год
Защитник сети Сергей Яремчук Киберкоп, или Конец виртуального мира Дмитрий Аксенов Контрольная сумма на защите Linux/FreeBSD Сергей Яремчук Минимум усилий на защиту DNS Сергей Ропчан Неявный самоконтроль как средство создания неломаемых защит Крис Касперски Обнаружение телекоммуникационных атак: теория и практика, snort Павел Закляков Общий обзор наиболее часто применяемых техник компьютерных атак и защиты от них Александр Потемкин Очередная веская причина задуматься о переходе с ОС Windows на альтернативу Виктор Игнатьев Переполнение буфера в Windows NT/2000/XP Станислав Гошко Перехват Shell через YaBB Виктор Игнатьев Построение переносимого Shell-кода для Windows-систем Станислав Гошко Система криптографической защиты информации Владимир Мешков Советы по безопасной веб-аутентификации Игорь Тетерин Сравнение сетевых сканеров безопасности Дмитрий Никсов, Петр Рудель Технологии протоколирования Honeypot в обеспечении безопасности сетевых Unix-систем Антон Даниленко Три составных части защиты Сергей Яремчук Удобнее, эффективнее, лучше: snort + MySQL Павел Закляков
№11(12) №1(2) №6(7) №1(2) №7(8) №10(11) №1(2) №9(10) №8(9) №6(7) №9(10) №4(5) №5(6) №1(2) №5(6) №7(8) №11(12)
HARDWARE
№
Вторая жизнь модемов Павел Закляков Глубоководное погружение в чипсет Intel 875P Крис Касперски Основы систем хранения данных Алексей Серебряков Плохое электропитание, или «Грабли» с UPS Павел Закляков Работа с жестким диском на программном уровне Владимир Мешков
№12(13) №6(7) №3(4) №8(9) №9(10)
ПРОГРАММИРОВАНИЕ
№
ColdFusion или, возможно, лучшее решение для создания динамических сайтов Александр Меженков Java - магия отражений Даниил Алиевский Javа: магия отражений. Часть II. ClassLoader – скрытые возможности Даниил Алиевский Java: магия отражений. Часть III. Компиляция Java средствами Java Даниил Алиевский Java: работа с файлами Даниил Алиевский Python глазами DBA Олег Попов Брандмауэр Владимир Мешков Брандмауэр. Часть II Владимир Мешков История одной разработки, или Как мы делали siteMETA Андрей Коваленко Итоги акции «Задай свой вопрос разработчикам поисковых систем», проводимой совместно с Всероссийским Клубом Веб-разработчиков Можно ли защитить веб-страницы от анализа исходного кода? Даниил Алиевский Некоторые недокументированные функции Java Даниил Алиевский Пакетный фильтр Владимир Мешков Перехват системных вызовов в ОС Linux Владимир Мешков Перехват системных вызовов в ОС Linux. Часть 2 Владимир Мешков Практические советы по восстановлению системы в боевых условиях Крис Касперски Программирование сервисов в Windows 2000 Всеволод Стахов Работа с базами данных на Perl Владислав Гошко Работа с текстом, или философия Perl Коновалов Евгений Регулярные выражения и поиск текста в Perl Владислав Гошко Стеммер. Морфологический анализ для небольших поисковых систем Андрей Коваленко
№12(13), декабрь 2003
№1 №1 №1(2) №2(3) №7(8) №7(8) №1(2) №2(3) №1(2) №3(4) №3(4) №3(4) №2(3) №3(4) №5(6) №12(13) №1 №9(10) №1 №8(9) №1
Управление сессиями в ColdFusion, или Здравствуйте, я – ваша тетя Александр Меженков Эффективное использование памяти в Perl при работе с большими строками Даниил Алиевский
№1
ОБРАЗОВАНИЕ
№
CommerceML – стандарт обмена коммерческой информацией в формате XML Елена Ртищева LTSP – вторая жизнь старых компьютеров Сергей Яремчук Mac OS X или То, что должен знать каждый про Macintosh, Apple и операционные системы Александр Потемкин Взаимные функциональные зависимости Андрей Филиппович Доступный Linux в каждую школу! Виктор Мельников, Андрей Шевченко Коды Рида-Соломона в практических реализациях, или Информация, воскресшая из пепла III Крис Касперски ЛВС: управляемость, надежность, масштабируемость Денис Еланский Могущество кодов Рида-Соломона, или Информация, воскресшая из пепла Крис Касперски Обучающие ситуационные центры Андрей Филиппович Обучение через Интернет – это возможно? Ольга Игошина Пингвин идет в школу Сергей Голубев Полиномиальная арифметика и поля Галуа, или Информация, воскресшая из пепла II Крис Касперски Скупой платит дважды, а умный использует GNU Public License Павел Закляков
WEB
№1(2)
№1 №12(13) №7(8) №1 №1(2) №11(12) №3(4) №8(9) №5(6) №7(8) №1(2) №10(11) №9(10)
№
Fusebox в помощь веб-программисту Андрей Уваров, Дмитрий Горяинов PHP Сергей Яремчук Выбор веб-сервера: почему Apache? Дмитрий Галышев Интернет-операционные системы Игорь Тетерин Конвертирование из Excel в HTML: корректно, качественно, просто Алексей Мичурин
№11(12) №5(6) №4(5) №4(5) №12(13)
IMHO
№
Вооруженное до зубов перемирие, или Я – то, чего не может быть! Татьяна Ильченко Почему OpenSource? (Точка зрения разработчика) Владимир Попов Рецепты правильного трудоустройства Крис Касперски Этика сисадмина Андрей Гуселетов
№10(11) №3(4) №9(10) №2(3)
ПОЛЕЗНЫЕ СОВЕТЫ
№
Кто предупрежден – тот вооружен Михаил Торчинский
№11(12)
ИЗ ЛИЧНОГО ОПЫТА
№
Каким видится хороший системный администратор Вячеслав Калошин
№7(8)
КАК ЭТО БЫЛО
№
Воспоминания замечательных дней: заря компьютеризации России и борцы с железными конями той эпохи… Алексей Костромин
№11(12)
ЖЕНЩИНА И КОМПЬЮТЕР
№
Почему мало женщин в компьютерных компаниях Вячеслав Михалев Уступите место женщине Евгения Саблина
№1 №1
93
подписка
Продолжается подписка на I полугодие 2004 г. Более подробная информация на сайте www.samag.ru в разделе «Подписка»
Единый подписной индекс:
81655 по каталогу агентства «Роспечать»
Рады видеть Вас нашими читателями!
№12(13), декабрь 2003
95
СИСТЕМНЫЙ АДМИНИСТРАТОР №12(13), Декабрь, 2003 год РЕДАКЦИЯ Исполнительный директор Владимир Положевец Ответственный секретарь Наталья Хвостова sekretar@samag.ru Технический редактор Владимир Лукин Научно-технические консультанты Дмитрий Горяинов Руслан Иванов Валерий Цуканов РЕКЛАМНАЯ СЛУЖБА тел.: (095) 928-8253 (доб. 112) факс: (095) 928-8253 Константин Меделян reсlama@samag.ru Верстка и оформление imposer@samag.ru maker_up@samag.ru Дизайн обложки Николай Петрочук 103012, г. Москва, Ветошный переулок, дом 13/15 тел.: (095) 928-8253 (доб. 112) факс: (095) 928-8253 Е-mail: info@samag.ru Internet: www.samag.ru РУКОВОДИТЕЛЬ ПРОЕКТА Петр Положевец УЧРЕДИТЕЛИ Владимир Положевец Александр Михалев ИЗДАТЕЛЬ ЗАО «Издательский дом «Учительская газета» Отпечатано типографией ООО «Мастер Печати» Тираж 5700 экз. Журнал зарегистрирован в Министерстве РФ по делам печати, телерадиовещания и средств массовых коммуникаций (свидетельство ПИ № 77-12542 от 24 апреля 2002г.) За содержание статьи ответственность несет автор. За содержание рекламного обьявления ответственность несет рекламодатель. Все права на опубликованные материалы защищены. Редакция оставляет за собой право изменять содержание следующих номеров.
96
ЧИТАЙТЕ В СЛЕДУЮЩЕМ НОМЕРЕ: Rule Set Based Access Control для Linux
Использование SQLite и PHP 5
Linux-системы, как многие другие в Unix-семействе, имеют известный недостаток в управлении доступом. Прежде всего это малое количество контролируемых прав доступа, состоящих в разрешении чтения, записи и возможности выполнения, и права эти можно установить только для владельца файла, членов группы-владельца и всех остальных. Иногда очень трудно вместить в предложенные ограничения даже пару десятков человек, при этом требуется более широкие возможности по описанию доступа к конкретному файлу. Дополнительно все программы, работающие от имени пользователя, имеют такие же права, как и сам пользователь, при этом совсем не учитывается важность самого объекта и необходимость работы с ним программы. Сам пользователь файла решает, являются ли данные файлы секретными или будут доступными остальным пользователям. Отсюда получается, что запущеная от имени суперпользователя программа имеет неограниченные возможности в системе и доступ к любому объекту (эту модель еще называют одноуровневой). Все хорошо, пока она не скомпрометирована, и тогда такое упрощение становится уже большим недостатком. Такая модель доступа называется Discretionary Access Control (DAC) и позволяет создавать системы, защищенные по классу С1.
Из-за лицензионной политики поддержка MySQL может быть не включена в окончательную версию PHP5. Поэтому, если мы планируем перейти на PHP5, обладающий расширенными возможностями благодаря новому «движку» – Zend Engine 2.0, нам стоит задуматься о достойной замене MySQL. Конечно, для профессиональных целей следует использовать PostgreSQL или Sybase, поддержка которых есть в PHP. Но если нам для небольшого проекта, например, гостевой книги или интерактивного прайс-листа, необходим небольшой и быстрый сервер баз данных, нам не обойтись без SQLite.
Эффективная работа с портами в FreeBSD Материал полностью посвящен портам в FreeBSD, хотя большинство примеров актуальны и для других *BSD. Система портов конкурирует с прекомпилированными rpm- и deb-пакетами, являясь более удобным средством для установки и удаления программ, обновления как отдельных, так и всех компонентов системы (стоит отметить, что порты не предоставляют альтернативу и являются ОС-зависимыми). Все основные системы BSD-семейства (NetBSD, OpenBSD, ну и конечно, FreeBSD) оснащены своими коллекциями потов. Аналогом портов обладают все «source-based» дистрибутивы GNU/Linux, самый известный из которых – Gentoo (http://gentoo.org) со своей системой портежей («portage»).
Наши партнеры