№1(26) январь 2005 подписной индекс 81655 www.samag.ru
Обзор дистрибутива SuSE Professional 9.2 Прокси-сервер oops: первые впечатления Как защищают программное обеспечение Путешествие из Perl в Excel Нити в Perl HOTSPOT – это просто! Программное управление файловой системой с помощью VBScript
№1(26) январь 2005
Восстановление NTFS Организация общего доступа в Интернет и защиты от вторжений на основе Kerio WinRoute Firewall 6
оглавление ТЕНДЕНЦИИ АДМИНИСТРИРОВАНИЕ SuSE 9.2 снаружи и изнутри
сетевых сервисов 2 Защита с помощью stunnel Часть 2 Андрей Бешков
46
tigrisha@sysadmins.ru
Алексей Барабанов alekseybb@mail.ru
Linux из Редмонда: обзор Lycoris Desktop/LX
3 Все в одном, или Hogwash как пример Gateway-IDS Сергей Яремчук
50
grinder@ua.fm
Валентин Синицын val@linuxcenter.ru
Прокси-сервер oops: первые впечатления
8 ПРОГРАММИРОВАНИЕ Путешествие из Perl в Excel Сергей Супрунов
Сергей Супрунов amsand@rambler.ru
12
Программное управление файловой системой с помощью VBScript
56
amsand@rambler.ru
Нити в Perl Алексей Мичурин
62
alexey@office-a.mtu-net.ru
Иван Коробко ikorobko@prosv.ru
HOTSPOT – это просто! Андрей Платонов Platonov@tayle.com
БЕЗОПАСНОСТЬ Организация общего доступа в Интернет и защиты от вторжений на основе Kerio WinRoute Firewall 6 Роман Марков stepan-razin@newmail.ru
Защита файловой системы при помощи нестандартного использования снапшотов в программе ShadowUser Денис Батранков denis@gov.ru
Как защищают программное обеспечение Крис Касперски kk@sendmail.ru
Сетевой полицейский
17 WEB JpGraph 22
Кирилл Сухов
Веб-сервис для разработчиков сайтов Даниил Алиевский
grinder@ua.fm
№1, январь 2005
77
daniel@siams.com
HARDWARE 28 Запись дисков CD-R/RW в Linux Часть 3 Владимир Мешков
78
ubob@mail.ru
ОБРАЗОВАНИЕ 35 Обучение при помощи ATutor Сергей Яремчук grinder@ua.fm
84
Восстановление NTFS – 38 undelete своими руками Крис Касперски kk@sendmail.ru
Сергей Яремчук
70
geol@altertech.ru
42 BUGTRAQ
88 49, 61, 76, 83 1
тенденции Новые технологии HP 25 января в отеле «Пента Ренессанс» прошла пресс-конференция компании HP, посвященная представлению новых серверов семейства HP Integrity среднего и старшего уровня на базе нового процессора Madison9M. Во вступительном слове Дмитрий Пенязь, руководитель подразделения бизнес-критичных серверных решений в России и странах СНГ, рассказал о стратегии развития бизнес-критических систем HP и причинах перехода на архитектуру Intel Itanium 2.
Äìèòðèé Ïåíÿçü, ðóêîâîäèòåëü ïîäðàçäåëåíèÿ áèçíåñ-êðèòè÷íûõ ñåðâåðíûõ ðåøåíèé â Ðîññèè è ñòðàíàõ ÑÍÃ. Îëåã Âàñüêîâ, ìåíåäæåð íàïðàâëåíèÿ ñåðâåðíûõ ðåøåíèé äåïàðòàìåíòà òåõíîëîãè÷åñêèõ ðåøåíèé, HP Ðîññèÿ
В процессоре Intel Itanium 2 повышена частота до 1.6, 1.5 Ггц, увеличен кэш второго уровня до 9 Мб. За счет бинарной совместимости ОС с двухпроцессорными модулями HP mx2 и процессорами Intel Itanium 2 6M замена процессоров не требует перекомпиляции приложений, а одинаковый процессорный разъем и совместимость с наборами микросхем HP zx1 и HP sx1000 призваны обеспечить легкую миграцию на Itanium 2. Повышена масштабируемость и гибкость в Linux-решениях: вдвое увеличено количество процессоров – с 8 до 16 под управлением SUSE Linux Enterprise Server 9 на базе последней версии ядра 2.6, добавлены расширенные возможности по виртуализации с использованием Global Workload Manager. Усилена безопасность и добавлены новые возможности управления вычислительными нагрузками в HP-UX 11i. Для Windows добавлены новые возможности Systems Insight Manager и Intergity iLO. Также на серверах HP Integrity теперь работает операционная система OpenVMS 8.2. Система работает на 3 аппаратных платформах – VAX, Alpha и Itanium. Поскольку эта ОС построена на базе общих исходных текстов, это позволит в дальнейшем выпускать модули модернизации ОС сразу для HP Intergity и HP AlphaServer. OpenVMS 8.2 поддерживает «смешанные» кластерные конфигурации, состоящие из узлов HP Integrity и HP AlphaSever (SSI до 96 узлов с расстоянием до 800 км). По заявлениям сотрудников HP кластеры из 3 платформ официально не поддерживаются, но также работают. Продолжаются работы в направлении виртуализации. В HP Virtual Server Environment внесены следующие усовершенствования: для платформы Windows – оплата по принципу коммунальных платежей (HP Pay Per Use for Windows), для HP-UX 11i и Linux – ПО управления вычислительными
2
нагрузками, кластерное ПО HP Serviceguard для HP-UX 11i и Linux для повышения доступности в средах Oracle и SAP и многое другое.
Кирилл Тихонов
Череда новогодних UNIX-релизов Первого января состоялся выпуск очередного (четвертого) обновления к последней стабильной версии Debian GNU/Linux (3.0, «woody»). В rev4 представлены накопившиеся за последний месяц заплатки к найденным уязвимостям, доступные на security.debian.org, и незначительные исправления ошибок. Михльмаер, лидер проекта, тем временем, сообщает, что новая стабильная версия дистрибутива – «Sarge» – появится «в начале этого года». 4 января Mandrakesoft анонсирует свои новые Linux-продукты для корпоративных пользователей: Corporate Server и Corporate Desktop, оснащенные всем лучшим из наработок компании в сочетании с открытым и коммерческим ПО, а также с качественным уровнем обслуживания и 5-годовой поддержкой. Патрик Волкердинг, несмотря на продолжающиеся исследования состояния здоровья, выпускает бета-релиз Slackware 10.1, а также просит всех пользователей не беспокоиться о будущем системы: она в надежных в руках и без поддержки не останется. 19 января до восьмой (8.0) версии обновляется популярная и многофункциональная открытая база данных PostgreSQL, для которой серверная Win32-платформа становится «родной». 25 января выходит в свет очередной стабильный релиз FreeBSD из четвертой ветки – 4.11-RELEASE. Все традиционно: патчи, поддержка новых устройств, небольшие улучшения.
Sun и Open Source Sun Microsystems продолжает подчеркивать свою благосклонность к открытым и бесплатным проектам: сначала компания выкладывает для свободного скачивания Linuxсистему Java Desktop System 2.0, а затем и исходники Java 6 «Mustang». Кроме того, представители Sun не перестают говорить об открытии Solaris, и в конце месяца осуществляется первый шаг уже широко разрекламированной акции: структура DTrace, одна из составляющих операционной системы, опубликована под Open Source лицензией CDDL. В сети появляется веб-сайт, посвященный проводимой Sun кампании, – www.opensolaris.org. Также поддержку Open Source в очередной раз демонстрирует и IBM, предоставив в свободное пользование 500 своих патентов.
Очередные пополнения в Linux-группах AMD и RealNetworks становятся спонсорами грядущей конференции Desktop Summit, учрежденной компанией Linspire и посвященной обсуждению открытого программного обеспечения. Китайские разработчики из Red Flag Software, активно готовящие к лету релиз Asianux 2.0, примыкают к Linux-лаборатории OSDL. А позже в OSDL приходит и Триджелл, автор Samba, который, став вторым после Линуса Торвальдса «OSDL Fellow», продолжит работу над «критически важным компонентом для Linux» при поддержке глобального Linux-консорциума.
Составил Дмитрий Шурупов по материалам www.nixp.ru
администрирование
SuSE 9.2 СНАРУЖИ И ИЗНУТРИ ОБЗОР ДИСТРИБУТИВА SuSE Professional 9.2
АЛЕКСЕЙ БАРАБАНОВ Как известно, с 8 ноября прошлого года официально начались продажи новейшего дистрибутива от SuSE с номером 9.2 [1]. В результате бурного развития процессов глобализации уже 11 ноября можно было заказать этот дистрибутив на nixp.ru [2], и спустя всего две недели после начала продаж один из таких заказов был доставлен мне. Еще немного, и можно будет получать новые выпуски SuSE раньше, чем сами трудолюбивые немцы увидят их в магазинах, точно так же, как и последние голливудские фильмы раньше американцев. Это не шутка, ибо выложить на ftp полученный дистрибутив в нашей стране можно было бы прямо тогда же, а вот сама SuSE смогла разместить версию ftp на официальных зеркалах [3] лишь 5 января 2005 года, то есть, как обычно, спустя пару месяцев. Теперь делюсь некоторыми впечатлениями. Кто ожидает услышать подробное step-by-step по настройке станции на SuSE, увы, не найдет этого. Здесь лишь некоторая информация и личные ощущения от последнего дистрибутива в сравнении с предыдущими. Скриншоты экранов и реклама «все ставьте SuSE» тоже представляется малоинформативной именно потому, что установка системы не представляет проблемы в подавляющем большинстве случаев, и поэтому приведение доказательств ее успешного проведения лишь вызывает сомнения в адекватности респондента. Хотя желающие могут полюбоваться снимками экранов на сайте SuSE [1], то есть теперь уже на разделе сайта Novell. Итак, начинаем установку на простенькое железо iC1700i845+ti4200+lcd15”. Все назначаем «по дефолту». Сразу заметно, что заставки установщика обрели «казенную» новелловскую стилистику. Собственно SuSE и так не отличался игривостью MDK (пингвинчики во всяких видах и проч.), поскольку делался прагматичными немцами, но теперь даже окантовка модальных окон linuxrc получила засечки в стиле MS Windows-286. Если судить по экрану загрузки установщика системы, то все постепенно обретает черты посиневшей Netware. Еще одно почти косметическое изменение произошло с кодом управления заставкой загрузчика. Уже привычный код F2 для включения детализации изменен на Esc, что плохо, поскольку это общепринятый код отмены, и если он случайно «зависнет» в буфере или просто продублируется из-за неисправной клавиатуры, то его может получить первое загруженное приложение. Такой выбор можно объяснить только влиянием Novell и стереотипами виндового GUI. В этой версии установщика, как и в предыдущей, снова
№1, январь 2005
предлагается русский язык, и причем вполне корректно, если не считать фразы вроде «Кликните на любом заголовке, чтобы сделать изменения» и странное изменение числа с «Настройка устройства» (одного!) на «Настройку оборудования» (уже многих) при движении по этому меню. То есть русский язык можно смело выбирать без риска получить нечитаемые сообщения на экране. Тем более это приятно для жителей зоны GMT+3, которая ставится в этом случае автоматически, как и вообще вся остальная локализация для «Европа/Россия», в том числе ru_RU.UTF-8 и переключение языка ввода через <Ctrl+Shif>. Не забыли даже русскую локализацию в KDE, что ранее бывало частенько. Хотя в важных случаях, когда надо получить однозначный и вразумительный ответ от пользователя, установщик снова теряет доверие к русскому переводу и переходит на привычный английский. Например, после уточнения параметров установки подтверждение требуется на англо-русском, предлагая выбор между «Назад» и «Install». Далее все как обычно. Снова SuSE по умолчанию предлагает ставить reiserfs, к которой идеологи компании испытывают труднообъяснимую мужскую симпатию. Если кому еще не известно, то в процессе установки доступны дополнительные консоли через <Alt+F№>, на которых можно проследить как ход установки, так и подправить что-то. Например, подгрузить недостающие модули или удалить что-то, если установка идет поверх старой версии. Итак, установка началась. В прогнозе заявлено, что она завершится через 38 минут. Причем в этой версии время считается как до окончания всей установки, так и до запроса нового CD. То есть, теоретически до запроса очередного CD можно устроить легкий кофе-брейк. Но скучать и перекуривать некогда. Выходим, как и предупреждали, в соседнюю консоль и подсматриваем, в каком режиме происходит установка. По тривиальному запросу «ps xua» узнаем, что y2base запускает для установки каждого пакета нечто вроде следующего (в фигурных скобках комментарии автора): rpm –root /mnt –dbpath /var/lib/rpm -U –-persent --nosignature {à âäðóã ìàíòåéíåðû «ëåâûå» ïîïàäóòñÿ} --force {ñèñòåìó ñòàâèòü, çàòèðàÿ âñå êîíôëèêòíûå ôàéëû} --nodeps {àâòîðû linuxrc âîîáùå íå äîâåðÿþò íèêîìó èç suse/people} --ignoresize {èãíîðèðîâàòü, òàê âñå, «äî êó÷è»!} /var/adm/YaST/InstSrcManager/IS_CACHE_0x00000001 ↵ /MEDIA/suse/...*.rpm
3
администрирование Вопреки тому, что в формате rpm присутствуют связи, и в базе rpm-пакеты регистрируются тоже с учетом связей, и сам дистрибутив SuSE относится к rpm-дистрибутивам, но по давней традиции и в силу происхождения SuSE от Slackware установщик этого чудного изделия напрочь игнорирует преимущества формата rpm перед tgz. И несмотря на такую явно беспроигрышную манеру установки инсталляция в первый раз «замерзает» на файле fonts-config20041001-2. Выяснение источника проблемы указывает, что процесс rpm с номером 4062 имеет статус D+, что, скорее всего, не лечится. Огорчению нет конца – а вдруг fonts-config «битый»? Ведь использовался не оригинальный диск, а всего лишь дубликат, выполненный на непрофессиональном оборудовании. Но что делать, надо спасать ситуацию. Выручают, как обычно, «три заветные кнопки». И здесь получаем второй сюрприз! Эксперимент проводился на компьютере, где уже ранее стоял SuSE 9.1 и одновременно с этим была рабочая копия Windows. Но вот незадача, у коллектива SuSE кроме симпатии к Хансу Рейзеру есть еще одна – к разработчикам GRUB. И они усиленно насаждают именно его в качестве системного загрузчика. Так как вторая стадия GRUB находилась на разделе, который был только что сформатирован в процессе установки, то Windows стал недоступен. Использование другого загрузчика, например LILO, могло бы избавить пользователей от подобных проблем. Короче, отступать некуда, надо ставить SuSE во что бы то ни стало. Во второй раз выбираем минимальную конфигурацию установки. Система прогнозирует установку пакетов общим объемом 350 Мб, ставится только с первого CD и предполагает время своей установки в 5 минут. Надо отметить, что не обманывает, ставится успешно именно за 5 минут. После первой перезагрузки YaST запрашивает пароль суперпользователя, предлагает настроить сеть и сразу же установить межсетевой экран. Последнее так же приятно, как и неожиданно. Далее следует предложение создать пользовательские бюджеты. Здесь надо отметить еще один положительный момент. Теперь SuSE по умолчанию сразу воспринимает длинные пароли, а не редуцирует их до 8 символов. Из негатива – то, что в минимальную установку снова не вошел mc. Эта утилита периодически вносится в минимальную систему, поскольку рациональна и удобна, и с неизменным постоянством изымается, поскольку презираема юниксовыми снобами. В релизе SuSE 9.2 снобы победили. А может, победило соображение, что mc собирается обычно с зависимостями от библиотек Xfree86 и множества утилит, а этого стараются избегать в минимальной установочной системе. Полностью минимальная система занимает 705 Мб дискового объема. Это несколько больше, чем размеры подобных установок большинства дистрибутивов, и практически вплотную приближается к разумному пределу для понятия минимальное в отношении Linux-дистрибуции, поскольку система большего объема уже не сможет быть клонирована с помощью CD без компрессии. Но успешная установка показала, что с копией дистрибутива все ОК. Чтобы не заниматься утомительным перебиранием CD, дистрибутив с CD-дисков переносим на DVD
4
по известной методе [4] и устанавливаем так, как и планировалось, со всеми настройками по умолчанию. Конечно, как не перекладывай дистрибутив с CD на DVD, все равно версия, поставляемая на CD, содержит менее двух с половиной тысяч пакетов, что совершенно не удовлетворительно для SuSE и совершенно недостаточно для работы. Скажем так, непривычна подобная бедность пользователям SuSE. Работая с продукцией этой фирмы, практически не приходится прибегать к использованию пакетов из других источников, кроме установочных носителей. И к этим прекрасным привычкам возвращает использование двухслойного DVD из дистрибутива SuSE, полученного из того же источника, что и первая копия [1]. Число размещенных там пакетов приближается к привычному пределу в четыре тысячи. Дифференциальный список составляет 1623 пакета [5]. Там очень много достаточно важных элементов. Например, все относящееся к IP-телефонии AtaAuto, asterisk, bayonne и весь набор openh323. Все приложения, необходимые для создания вычислительных кластеров и кластеров heartbeat. Важные серверные приложения arpwatch, apcupsd, nagios. То, без чего просто не построить сетевой коммутатор, bridge-utils и ebtables. Большое число приложений из разряда security, например tynyca и набор утилит и библиотек для работы с электронными ключами и картами pcsc. Большинство пакетов разряда *-devel также размещено только на DVD, включая и компилятор для NET. В разряд «не для всех» попал даже PostgreSQL и совершенно необходимый на взгляд автора leafnode. Короче, крайне не рекомендуется использовать дистрибутив на CD, чтобы не испортить впечатление от нового SuSE, особенно для тех, кто сталкивается с этим дистрибутивом впервые. Поэтому откладываем урезанный вариант в коллекцию и далее работаем только с полной DVD-версией. Проверка на железе проходит безупречно. Более интересный результат показывает установка в среду виртуальной машины VMware5 beta, запущенной под SuSE 9.1. Установщик неправильно понимает виртуальную видеокарту и переходит на общение в текстовом режиме, хотя и предлагает установку графической среды. Которая, будучи запущенной после перезагрузки, не только отлично работает, но и после установки режима с большим разрешением, чем стартовые 640 на 480, прекрасно его держит. Все остальное также безупречно. То есть, такая проверка выявляет отсутствие должных деловых контактов между командой разработчиков linuxrc и командой, совершенствующей YaST. Дистрибуция SuSE является очень динамическим образованием. Релизы выпускаются по меньшей мере дважды в год, а между выпусками постоянно вносятся исправления. Уже много лет подряд главным признаком скорого появления очередного дистрибутива является создание на официальных зеркалах SuSE [3] директории с обновлениями к еще не выпущенному дистрибутиву. Итак, обновления – и благо, и источник беспокойства. Зачастую их объем весьма значителен. Так, например, спустя менее 2 месяцев после начала продаж объем обновлений к новому SuSE уже превышает 500 Мб. Это приводит к тому, что свежепоставленная система сразу же требует потратить значительный трафик на ее доведение до соответствия всем последним изменениям, в том числе и по безопасности. Поэтому разум-
администрирование но или заранее скачать обновления и добавить их к дистрибутивному DVD, как подсказано по ссылке [4], или сделать специальный patch-диск. Для создания такого диска надо разместить в корне подготовленного ISO-имиджа цепочку вложенных директорий i386/update/9.2/*, подобно тому как они размещаются на ftp-зеркалах, например, в ftp.mirrors.net.ar/pub/suse/i386/update и так далее. Внутри должна обязательно присутствовать директория patches/, содержащая информацию о патчах, и директория rpm/, в которой внутри директорий одноименных с названиями архитектур, а именно i586, noarch и x86_64, размещены собственно патчи. Это все. Достаточно создать такие директории, наполнить их файлами с ftp, записать на диск, и тогда можно выбирать в YaST пункт меню «Обновление с patch CD» и устанавливать апдейты прямо с созданного диска. Теперь снова вернемся к вопросу переноса дистрибутива SuSE на DVD, но уже не с набора CD, а с дорогого двухслойного на обычный и дешевый. Изначально размер имиджа такого оригинального Double Layer DVD составляет 7680 Мб. Если выкинуть директорию, содержащую файлы для 64-битной архитектуры, то останется 4971 Мб. Опять недостаточно. Значит, вопрос в том, что сократить еще. Теоретически, надо удалить некоторое число пакетов общим объемом 200 Мб. Самое простое – выкинуть локализацию, кроме русской и 5 европейских языков – английского, немецкого, французского, испанского и итальянского. Из уважения к Барселоне оставим еще и каталонский. Украинский само собой тоже. Итак, удаляем «лишние» локализации из OpenOffice, aspell, ispell, kde3-i18n, koffice-i18n, mozilla, myspell, ted. Общим числом 160 и общим объемом на 491 Мб [7]. Остается 4497 Мб, которые и укладываем в новый имидж. В итоге получили 4352 Мб в готовом образе DVD. Иначе говоря, проявив немного более решительности в избавлении от лингвистических излишков, можно еще получить место для добавления нужных утилит из сборников третьих производителей [8]. Например, тот самый Mplayer сборки из misc/ packman/suse/9.2/. Важно отметить, YaST опознает диск в непримонтированном состоянии по меткам ISO9660. Ключевыми являются метки Volume, Publisher и Application. Если установка некоторого дистрибутива происходила с диска, который был далее модифицирован, то новый ISO9660имидж надо создавать точно с такими метками, иначе YaST его не «почувствует». Отметим некоторые метрики. В SuSE92 для архитектуры IA32 предложено 332 пакета, а для x86_64 уже 3972! Если учесть, что 6 пакетов в IA32 продублированы в i586 и в i686, то получается еще меньше, а именно 3926. Кстати, во всех дальнейших подсчетах продублированные пакеты создают некоторое расхождение в полученных суммах с листингами, созданными утилитой diff и другими. В версии CD всего 2311 пакетов в числе которых 6 для i686, то есть реально 2305. Вот итоговые числа, сведенные для наглядности в таблицу.
№1, январь 2005
Разберемся, в чем же дело. Может, стоит всем дружно перейти на новую 64-битную архитектуру. Создадим списки пакетов в разделах i586 и x86_64 с помощью простенького скрипта вроде следующего: # ls -l /mnt/suse/i586 | perl -ni -e ↵ '@s=split(/\d\d\:\d\d); @q=split(/-(\d)*\./,$s[1]); ↵ print $q[0], "\n"' | sort -u >i586.list
И тоже для другой архитектуры. А потом сравним полученное с помощью diff: # diff x86_64.list i586.list > x86_64-i586.list
Заглянув в полученный дифференциальный список, раскрываем секрет несоразмерно большого числа пакетов для x86_64. В разделе x86_64 дополнительно уложены пакеты, содержащие 32-битные версии. Это вызвано спецификой обработки платформенных зависимостей менеджером rpm. Например, arts из i586 содержит полную версию для IA32. Аналогичный пакет arts из x86_64 содержит полную версию для 64-битной архитектуры, а добавка arts-32bit содержит только библиотеки от архитектуры IA32. Теоретически эти библиотеки можно было бы экстрагировать из пакетов раздела i586, но практически rpm так не умеет делать, и поэтому мы обречены произвести второй подсчет, но уже исключив пакеты с суффиксом 32bit в имени. # cat x86_64.list | grep -v 32bit >x86_64only.list # diff x86_64only.list i586.list > x86_64-i586.list
Полный результат можно посмотреть по ссылке [9]. Этот список сообщает, что счастливые обладатели компьютеров на 64-битных процессорах не смогут пользоваться практически всеми имеющимися в дистрибутиве эмуляторами от FAUmachine до wine и dosemu. Им будет недоступно огромное число драйверов, включая и драйвера софтмодемов. Будут лишены они и OpenOffice вместе с Acroread, и RealPlayer. Заодно и etherboot с netboot. Короче, тестировать такие компьютеры уже можно, но работать все-таки лучше на традиционных. Но уверен, что строка чисел, относящихся к FTP-версии, также должна вызвать вопросы. Традиционно в SuSE версия, подготовленная для FTP, то есть практически для бесплатного скачивания, всегда выходила позже, что очевидно, и, как правило, с ограничениями, которые были вызваны не проблемами хостинга, а тем, что в «коробочную» версию добавлялись программные продукты, специально подготовленные для промоутинга. Например, демо Loki Games или релизы VMWare. Конечно, на FTP это отсутствовало. Но со временем разница между «коробкой» и FTP становилась все меньше и меньше. Настоящий релиз не исключение. В категории i586 в FTP недостает лишь BEAJava2-JRE, BEAJava2SDK, что совсем не обижает, ну сколько же можно коллекционировать Java-клонов, особенно производства таких компаний, которые не желают открыто размещать свои продукты. А в категории x86_64 даже наметилось превосходство FTP-релиза! Добавлен «свеженький» драйвер km_usbvision для веб-камер Zoran/Nogatech USBVision. Другими словами, FTP-версия ничем не уступает, а если учесть то, что пакеты, в нее входящие, имеют более «свежие» индексы, то и пре-
5
администрирование восходит «коробочный» вариант, поэтому счастливые владельцы безлимитных подключений к Интернету могут смело выкачивать с зеркал SuSE [3] FTP-версию последнего дистрибутива и, переложив ее на DVD, как описано в [4], ставить на свои рабочие станции и сервера. Может сложиться впечатление, что в SuSE совершенно напрасно потратились на CD в своем дистрибутиве. Практически, да. Лишь одно оправдание есть для CD. Первый из них играет важную роль как спасательный диск и диск для установки минимальной системы. Точнее, установка SuSE производится в два этапа. На первом этапе система в базовом варианте устанавливается только с первого диска. Затем происходит перезагрузка, и далее ставятся недостающие пакеты с других дисков, если это необходимо. Поэтому набор пакетов на первом диске является самодостаточным с точки зрения связей rpm [10]. Это говорит о высоком качестве сборки. Замечу, что до версии 7.3 SuSE – о таком можно было лишь мечтать. Инженеры SuSE постепенно, путем проб и ошибок, приходят ко многим очевидным для остальных истинам. Например, столь долго всех удивлявшие полной никчемностью, Live Evaluation CD начиная с версии 9.1 трансформировались в полноценные Live CD. Но вместо этого появилась новая странная вещь, так называемый SuSE-Linux-9.2-mini-installation.iso. Это загрузочная часть стандартного дистрибутивного носителя вместе с initrd установщиков и спасательных дисков. Как написано в сопровождающем этот артефакт README.txt, сие предназначено для установки никак не минимального, а полного релиза SuSE с удаленного примонтированного репозитория. Можно предположить, что это что-то вроде базовой системы Debian для установки с официальных зеркал. Но нет. Имидж этот лежит уже давно, а ftp-версия SuSE только-только появилась. Короче, загадочно назначение этого продукта мысли, если только не принять версию, что ftp-установщик выложили за пару месяцев до ftp-релиза изза неожиданного перевыполнения графика работ. Но есть надежда, что со временем все эти робкие попытки познания истины приведут к тому, что в SuSE догадаются соединить Live-CD, CD1 и псевдо-mini-installation в один имидж, выкинув все остальные CD из дистрибутива совсем. Проанализировав rpm-зависимости всего дистрибутива, а не только лишь первого CD, обнаруживаем небольшую проблему [11] в сборке одного пакета из OpenOffice. В начале отчета сборщика связей содержится сообщение об ошибке следующего содержания: «При обработке пакета Open Office_org-tr-1.1.3-16.i586.rpm, который уже в группе 65, обнаружено что он взаимно связан с пакетом OpenOffice_org1.1.3-16.i586.rpm, который уже в группе 66». Непонятно, чтото в чем-то, а не где-то... Посмотрим поточнее, что требует упомянутый в сообщении пакет и сравним это с аналогичным, так как речь идет об одном из локализующих добавлений в OpenOffice. # rpm --requires -qp OpenOffice_org-tr-1.1.3-16.i586.rpm ↵ | grep -v ^rpmlib OpenOffice_org = 1.1.3-16 OpenOffice_org-en-help fileutils
# rpm --requires -qp OpenOffice_org-it-1.1.3-16.i586.rpm ↵ | grep -v ^rpmlib
6
OpenOffice_org = 1.1.3-16 myspell-italian fileutils
Итак, пакет турецкой локализации расходится с пакетом итальянской локализации ровно в одном требовании – OpenOffice_org-en-help. Проверим, что в свою очередь требует этот пакет : # rpm --requires -qp ↵ OpenOffice_org-en-help-1.1.3-16.i586.rpm | grep -v ^rpmlib OpenOffice_org-lang
Следующий кандидат на проверку OpenOffice_org-lang отсутствует в списке пакетов. Но, запросив, список обеспечиваемых ресурсов у конфликтного пакета, получим : # rpm --provides -qp OpenOffice_org-tr-1.1.3-16.i586.rpm OpenOffice_org-lang ooo-i18n:/usr/lib/ooo-1.1/program/resource/vcl64590.res OpenOffice_org-tr = 1.1.3-16
Как видно, OpenOffice_org-tr ссылается сам на себя по цепочке. Значит, совсем не зря установка пакетов происходит без учета зависимостей rpm. И благодаря этому кандидаты на вступление в дружную европейскую семью могут не беспокоиться, у них не будет проблем в использовании SuSE. Но тем не менее каждый может заглянуть в spec в исходниках турецкого локализатора и узнать автора этой несуразности. Найденное есть сущая мелочь. Можно отметить высокое качество сборки дистрибутива. Предположим, что этот дистрибутив может быть помещен под управление apt без каких-либо существенных правок. Еще парочка релизов, и SuSE можно «из коробки» ставить не только YaST, но и apt и даже просто последовательно с помощью тривиального rpm. Снова вернемся к составу дистрибутива SuSE 9.2 на DVD. Там 7230 пакетов. Исключив 3298 тех, что относятся к x86_64, получим 3932 пакета, что на 1621 пакет больше, чем в CD версии. То есть дистрибутив на DVD напоминает тот самый, привычный всем SuSE, в котором обычно было всегда примерно 4000 пакетов. Пакеты «росли» и «толстели», старые «съеживались» и исчезали, новые приходили сразу изрядного объема. Все это увеличивало размеры дистрибутивных носителей, но число пакетов всегда оставалось в пределах 4 тысяч. Итак, если проблемы с турецкой локализацией ОpenОffice решат до принятия Турции в ЕС, то у SuSE 9.3 прекрасные перспективы. Хотя, если принять в расчет ускорение прогресса, благодаря которому последний минорный индекс 4 был только у SuSE 6.4, а минорный индекс 3 у SuSE 7.3, то шансов увидеть SuSE 9.3 гораздо меньше, чем SuSE 10.0. Но попробуем сравнить настоящий выпуск SuSE с предыдущим. Что происходит? Развитие, регресс или стагнация. Проведем сравнение по нескольким параметрам. Сначала по объему. В релизе 9.1 было 3446 пакетов для архитектуры IA32 и noarch. В 9.2 уже 3932 для IA32 и noarch и еще 3298 только для 64-битной архитектуры. Другими словами, объем вырос. Чего не скажешь о цене, что приятно. Предыдущий выпуск SuSE был переходным с точки зрения версии ядра. Но вопреки обычной практике, когда в переходном дистрибутиве предлагалось и новое ядро, и остав-
администрирование лялась возможность работы со старым, в 9.1 выбора не оставили и принудительно всех «пересадили» на ядро 2.6.4. И поскольку использованное в коробочной версии ядро оказалось неудачным, то впервые SuSE выпустила не просто исправляющий апдейт, а полную смену ядра на следующую версию 2.6.5. То есть в этом смысле релиз 9.1 явно не удался. В настоящем релизе используется ядро 2.6.8, что внушает доверие, учитывая его младший индекс и почти полугодовую историю эксплуатации ядер 2.6 в SuSE. Но с другой стороны, в новом дистрибутиве уже сменили версию Samba с 3.0.7 на 3.0.9. То есть «еще не вечер», а лишь первые пара месяцев из средней полугодовой «жизни» релиза. Теперь более подробно рассмотрим, что же конкретно было удалено из дистрибутива и что было добавлено взамен. Полный список очень велик [12]. Далее некоторые выдержки из него. ! Расстались с чрезвычайно необходимой игрушкой 3d_ chess, перестали играть в машинки racer, racer-addons и в прочую ерунду tuxeyes, xmine. Но обрели последние популярные средства IP-телефонии Asterisk вместе со спокойными вдумчивыми пазлом fillets-ng. ! Потеряли Keramic стиль в Gtk Geramik, а заодно и другие темы gtk-themes-20001105, но приобрели новые драйвера для софтмодемов Intel-536ep и Intel-537ep, выкинув при этом старые hsflinmodem, km_hsflinmodem. ! Вот сюрприз! Выкинули весь Xfree86! А взамен получили Xorg! ! Вот еще новинки для любителей. Детектор вторжения chkrootkit, инструментал для создания новомодных LiveCD – cloop и средство протоколирования аварийных завершений panicsel. За это выкидываем без колебаний cellular и coldsync! ! А вот этого и в самом деле жаль directory_administrator, logsurfer, webmin. Но, может, кого-то утешит появление необычайно нужного серверного средства dnsmasq. Шутка, конечно. Хотя полностью верно в отношении ulogd. ! И вот он – знак прогресса! Нет теперь этого музейного экспоната inetd, который уже давно является бесполезным дублем xinetd. А в утешение снова вернули симулятор историчеких версий UNIX – simh. Аналогично выкинут iSilo, но добавлен могучий dx от IBM. ! Оказался ненужным url_get. Вместо этого появился новый сетевой бэкап sesam_srv и монитор openhpi. ! Наконец кто-то догадался, что у xterm слишком много клонов, и выкинул eterm и wterm. К огорчению юниксовых снобов, выкинут новый VI клон nvi и ставшие ненужными rusers и rwall. ! Выкинут deliver и bulk_mailer, но добавлен почтовый сервер dovecot и обработчик входящей почты otrs. ! Стал для разработчиков SuSE не нужен и прекрасный веб-редактор quanta. Зато снова вернулся Tomcat в виде tomcat5 и вместе с struts и даже с servletapi. ! Как известно, производители ERP-систем переживают кризис. И вот следствие. Зачем SuSE спонсоры, которые не платят денег. Резолюция – выкинуть! Так избавились от sapdb. Но поскольку теперь Linux-прогресс двигают новые «лошадки», IBM и Novell, то они накидали в дистрибутив своего любимого всякого java-подобного puretls, oro, netcomponents, mx4j и еще очень много в разделе noarch
№1, январь 2005
с первой буквой «j» вплоть до ejb и даже cryptix. Но добили совершенно шеллом на все том же java bsh. Теперь не пользоваться java все труднее и труднее. ! Ну и напоследок, так как yast2 в развитии достиг небывалых высот, то отладочный плагин yast2-debugger ему стал не нужен. А вместо этого получили новые модули yast2-bluetooth, yast2-bootfloppy, yast2-irda, yast2-uml. Каждый волен расставить свои оценки напротив перечисленных пунктов. Но вряд ли оценки могут полностью негативными. Пользователи SuSE 9.2, вероятно, более приобрели, чем потеряли. Главное, что осталось в SuSE, это высокое качество и чисто немецкая добротность всего, что выходит под маркой SuSE. Для иллюстрации последнего утверждения сошлюсь на положительный опыт установки в SuSE 9.2 специального программного продукта Wine Rack, выпущенного к версии SuSE 9.0. Фактически это CrossOver Office, то есть специально собранный wine. Этот продукт ставится поверх нового SuSE и позволяет далее устанавливать в свою среду различные приложения для MS Windows. Например, как видно на снимке экрана [13], в KDE одновременно работают встроенный браузер Konqueror и IE6.
Полезные ссылки: 1. Официальный обзор SuSE 9.2: http://www.novell.com/ru-ru/ products/linuxprofessional/overview.html. Там же можно посмотреть и скриншоты с десктопов этого дистрибутива. 2. Покупка копии: http://www.nixp.ru/cdrom. Здесь вы получите точную копию с оригинала SuSE. Работа с этими копиями и описана выше. 3. Полная FTP-версия и обновления к «коробочному» выпуску: http://www.suse.com/en/private/download/ftp/int_ mirrors.html. 4. Как модифицировать дистрибутив: http://www.barabanov.ru/arts/how-to-modify-suse-dvd.html. Рекомендуется добавить к установочному DVD последние обновления, что поможет сократить онлайновые апдейты. 5. Список пакетов, размещенных только на DVD: http:// www.barabanov.ru/arts/suse92overview/suse92-dvd-cd.list 6. Покупка бокса: http://www.linuxcenter.ru/goods/1083.html. 7. Список пакетов, дополнительно удаленных с имиджа двухслойного DVD: http://www.barabanov.ru/arts/suse92 overview/suse92-removed.list. 8. Нестандартные добавления к SuSE: http://ftp.gwdg.de/ pub/linux/suse. Рекомендую добавить к установочному DVD последние обновления, что поможет сократить онлайновые апдейты. 9. Различия в наборах пакетов для разных архитектур: http:// www.barabanov.ru/arts/suse92overview/x86_64-i586.diff. 10. Список пакетов первого CD в порядке установки: http:// www.barabanov.ru/arts/suse92overview/suse92-cd1-table.rep. 11. Список пакетов дистрибутива SuSE 9.2 в порядке установки: http://www.barabanov.ru/arts/suse92overview/ suse92-dvd-table.rep. 12. Различия в составе дистрибутивов SuSE 9.2 и 9.1: http:// www.barabanov.ru/arts/suse92overview/suse92-suse91.diff. 13. Скриншот suse92, Wine Rack 9.0 и Internet Explorer v.6: http://www.barabanov.ru/arts/suse92overview/suse92-wineie6.png.
7
администрирование
LINUX ИЗ РЕДМОНДА: ОБЗОР LYCORIS DESKTOP/LX
ВАЛЕНТИН СИНИЦЫН Как и многое в этом мире, дистрибутив Lycoris Desktop/LX берет свое начало в 2000 году. На рубеже веков человек по имени Джозеф Чик (Joseph Cheek) решил сделать на базе Linux систему, доступную каждому, а заодно занять пустующую нишу настольных операционных систем для дома. Для достижения этой цели им была создана компания Redmond Linux Corp., зарегистрированная в Редмонде (штат Вашингтон). По странному стечению обстоятельств там же располагалась (и до сего момента располагается) штабквартира корпорации Microsoft, поэтому многие стали рассматривать это название не как производную от местоположения фирмы, а как тонкий намек на эквивалентность Windows. Производители настольных дистрибутивов вооб-
8
ще любят ассоциировать свои продукты и вездесущие «окна» в глазах потенциальных покупателей, однако немногим из них удавалось сделать это столь тонко и изящно. Под данной торговой маркой компания успела выпустить свой первый продукт, Redmond Linux Personal (декабрь 2001 года), а затем, в январе 2002 года сменила имя на геополитически нейтральное «Lycoris» (произносится «лайкорис», официальный сайт http://www.lycoris.com) и некоторое время спустя перебралась в городок Мэпл Уэлли (Maple Valley). Как было сказано в официальном пресс-релизе, ребрендинг являлся частью подготовки к продвижению на новые рынки и расширению модельного ряда. Последнее не заставило себя ждать. Redmond Linux превратился в Lycoris
администрирование Desktop/LX1. Для взыскательных пользователей был создан трехдисковый Lycoris Desktop/LX Deluxe со средствами разработки и исходными текстами, для владельцев «наладонников» – PocketPC Edition (ныне это направление развития заморожено в связи с отсутствием ресурсов). В июле 2003 года появилась на свет и версия для суб-ноутбуков – Desktop/ LX Tablet Edition. Помимо этого, компания предлагает различные дополнения (Pack), например, ProductivityPak и GamePak, речь о которых пойдет ниже. Первые версии дистрибутива распространялись бесплатно, а компания взимала деньги лишь с тех, кто желал приобрести коробочную версию. В конце прошлого – начале этого года данная бизнес-стратегия была пересмотрена и бесплатная Download Edition превратилась в оценочную версию (Evaluation Edition), срок использования которой ограничен 45 днями, а максимальное число компьютеров, работающих под ее управлением, – пятью. Кроме этого, Evaluation Edition включает только открытые приложения. Коммерческая версия не имеет подобных ограничений (т.е. может быть установлена на произвольное число компьютеров, но только для некоммерческого применения) и стоит 40 (Desktop/LX) или 50 (Desktop/LX Deluxe) долларов плюс еще пять, если вы предпочитаете красивую коробку обычному ISO-образу (или не имеете возможности загрузить несколько сотен мегабайт). В комплект поставки входит 30-страничное руководство по инсталляции, 60 дней технической поддержки по электронной почте (максимум 3 инцидента), а также Product ID, уникальный код, с помощью которого можно получить доступ к дополнительным услугам, представляемым Lycoris, например, фирменной коллекции программ Iris (http://iris.lycoris.com). В свою очередь Lycoris Desktop/LX Evaluation Edition доступен для загрузки с FTP-архива Ibiblio (ftp://ftp.ibiblio.org) и многочисленных зеркал. Его поддержка обеспечивается через сайт сообщества Lycoris (http://www.lycoris.org), где находится форум, полезные советы, списки часто задаваемых вопросов и даже кое-какие программы, собранные энтузиастами. Большая часть из них, к сожалению, подустарела. В данной статье мы рассмотрим возможности и некоторые детали устройства ОС Lycoris Desktop/LX 1.4 Evaluation Edition.
Генезис В основе Desktop/LX лежит дистрибутив Caldera OpenLinux, который в свою очередь базируется на ранних версиях Red Hat. На сегодняшний день Caldera в образе SCO Group ведет войну с миром Open Source, поэтому на помощь в поддержании «фундамента» Lycoris рассчитывать не приходится. Это накладывает на систему своеобразный отпечаток: вплоть до текущего выпуска в качестве рабочего стола по умолчанию в Desktop/LX использовался KDE 2. Впрочем, приобретенная в наследство от Red Hat пакетная система (RPM) позволяла особенно охочим до всего нового пользователям поставить KDE 3.x из любого удобного репозита1
2
рия (правда, слегка повредив специальную обработку-«лайкоризацию»), так что особых проблем это не вызывало. «Под капотом» Desktop/LX 1.4, фактический выпуск которой состоялся в сентябре 2004 года, скрывается Linux 2.4.27, XFree86 4.4.0 и KDE 3.2.3. В качестве офисного пакета используется KOffice. Пользователям, предпочитающим OpenOffice.org, придется раскошелиться на Lycoris ProductivityPak (40 долларов). Одним из крупных нововведений в версии 1.4 является специальная редакция Power Pack, включающая все возможности Desktop/LX Deluxe плюс CrossOver Office и btX2, закрытую технологию обработки и отображения шрифтов, разработанную компанией Bitstream. Все это удовольствие стоит 80 долларов. До настоящего времени единственным средством совместимости с Windows, доступным пользователям Lycoris Desktop/LX, был Wine. Любители поиграть могли также приобрести Gamepack (несколько свободно распространяемых игр + 1 месяц подписки на WineX, 30 долларов). Кроме того, в данный момент Lycoris широко рекламирует AI2 («AI в квадрате») – систему, обеспечивающую тесную интеграцию сторонних приложений с Desktop/LX, но, к сожалению, опробовать ее в действии мне так и не удалось.
Первое знакомство С чего начинается Lycoris Desktop/LX?. Как это ни парадоксально, с «ящерицы». Именно так, в переводе с английского, называется инсталлятор этой системы – Lizard. Впрочем, если вам придет в голову вставить дистрибутивный диск в привод компьютера, работающего под управлением Microsoft Windows, вы увидите не его, а стандартный мастер а-ля InstallShield, который предложит вам ознакомиться с лицензией, выбрать способ установки (с CD-ROM или гибких дисков) и перезагрузить систему. В процессе инсталляции обнаружилась одна неприятная особенность. Расположенный на компакт-диске с дистрибутивом GRUB отказывался загружать ядро на системах, имеющих менее 600 Кб свободной «нижней» памяти (lower memory). Это имеет место на ноутбуках, собранных на базе процессора Transmeta Crusoe. Чтобы решить данную проблему, мне пришлось загрузить уже установленный на компьютере Mandrakelinux, смонтировать в нем образ загрузочного диска Desktop/LX, скопировать ядро и организовать загрузку через LILO. Дальше все пошло как по маслу. Инсталлятор автоматически обнаружил CD-ROM с программными пакетами (судя по выводу на экран, я мог бы также разместить их на жестком диске или разделе NFS), после чего был запущен упомянутый выше Lizard. Независимо от того, сделали вы это в Windows-мастере или нет, «ящерица» предложит вам принять лицензионное соглашение. Из указанных в нем вещей нас сейчас будет особенно интересовать список компонентов, разработанных самой Lycoris2. Согласно данному документу, это My Linux System, Network Browser, панель управления Desktop/LX Control Panel и сопутствующие конфигурационные утилиты (Remote access
Компания настаивает на том, чтобы ее продукт называли «Lycoris Desktop/LX» или на худой конец просто «Desktop/LX», но уж никак не «Lycoris». Уважая права автора на свое произведение, мы будем следовать этому требованию неукоснительно. Как правило, выискивать области, подвергшиеся специальной доработке, приходится вручную. А тут – на тебе: на блюдечке с голубой каемочкой.
№1, январь 2005
9
администрирование control, Firewall control), поддержка протокола «exec:» для Konqueror (KIO_EXEC) и собственно инсталлятор (Software installer). Все перечисленные программы распространяются свободно. Памятуя об излишне «умном и самостоятельном» инсталляторе Linspire, хочется отметить, что Lizard предоставляет пользователю куда большую свободу действий. Особых похвал заслуживает опция «Обновить существующую систему» («Update Existing Installation»). В том, что касается разметки жесткого диска, Lizard предлагает несколько вариантов: использовать весь HDD, только свободное (неразмеченное) пространство, выбрать раздел или произвести разбиение вручную. Правда, к бочке меда прилагается своя ложка дегтя: поддерживается только файловая система ext3. Имеющиеся на диске разделы подкачки инсталлятор определяет и подключает автоматически. Процедура копирования пакетов в Lizard реализована весьма оригинально. Она начинается сразу же после разбиения жесткого диска и продолжается в фоновом режиме, о чем свидетельствует полоска-индикатор в нижней части экрана. Вы же тем временем продолжаете настройку своей будущей системы: указываете параметры сети, создаете пользователей (к чести создателей Desktop/LX отметим, что программа явным образом отделяет пароли обычных пользователей от системного пароля root, хотя их проверка на прочность опять же не производится), выбираете тип модема и видеокарты (оба списка достаточно обширны), указываете свой часовой пояс и включаете загрузку «других ОС» (по-видимому, под этим термином понимается Windows. По крайней мере стоящий на соседнем разделе Mandrakelinux инсталлятор проигнорировал). Покончив с этими делами, вы можете скоротать минуты, оставшиеся до конца инсталляции, раскладывая пасьянс. При выборе видеокарты советую вам быть особо осторожными с адаптерами типа «Generic SVGA». По не вполне понятной мне причине их поддержка в Lycoris Desktop/LX обеспечивается не XFree86 4.4.0, а XFree86 3.3.6, которая также входит в состав дистрибутива. Если до этого вы успели выбрать более «продвинутый» вариант (скажем, nvidia), возникнет патовая ситуация – файл настроек X-сервера будет содержать инструкции для XFree86 4.x, но при этом символическая ссылка «X» будет указывать на более старый сервер. В результате после перезагрузки система не сможет перейти в графический режим и вам придется вносить правки вручную из командной строки и vi. Добро пожаловать в Linux! Закончив с установкой, извлеките диск из привода CDROM и приготовьтесь войти в прекрасный мир Lycoris.
Встречают по одежке... После успешной перезагрузки и выбора правильной (в моем случае – единственно возможной) опции в меню GRUB, вы увидите графическую заставку с фирменной эмблемой Lycoris (цветочком «Flower Logo»). О том, что компьютер не завис, свидетельствует полоска-индикатор в правом нижнем углу экрана. Впрочем, вы можете посмотреть, что происходит «за кулисами», нажав волшебную кнопку <F2>. После подгрузки модулей ядра, монтирования файловых систем и старта всех необходимых демонов вам будет представлен
10
графический менеджер входа в систему. Используйте одну из учетных записей, созданных в процессе инсталляции. Первое, что бросается в глаза при виде рабочего стола Desktop/LX, – это прозрачная панель (см. рис 1). Несмотря на простоту эффекта, это выглядит очень стильно. Запустив одно-два приложения KDE, можно заметить, что все они используют визуальную тему Plastik. Как правило, разработчики настольных дистрибутивов стремятся создать свое собственное оформление, но, видимо, в Lycoris решили не изобретать велосипед и воспользоваться уже готовым решением. К сожалению, это негативно сказалось на качестве интеграции: приложения KDE и GNOME (например, входящие в стандартную поставку Desktop/LX GIMP 2 или Lycoris Web Suite, он же – Mozilla 1.7.3) выглядят по-разному.
Ðèñóíîê 1. Ðàáî÷èé ñòîë Lycoris Desktop/LX 1.4
На самом рабочем столе легко заметить пиктограммы My Linux System и Network Browser, заменяющих «Мой компьютер» и «Сетевое окружение», соответственно. Еще один из упомянутых в прошлом разделе компонентов, Desktop/ LX Control Panel, скрывается в главном меню (пункт System Management). Все три утилиты выдержаны в едином стиле, по своей структуре напоминающем соответствующие диалоги Windows (рис. 2), и реализованы очень оригинальным образом. Как нетрудно догадаться, они базируются на Konqueror. На самом деле, панели навигации в окнах My Linux System/Network Browser, а также различные разделы панели управления – это просто HTML-страницы, шаблоны которых хранятся в каталоге /usr/share/RedmondLinux/HTML, а сопутствующие сценарии на языке оболочки – в /opt/ redmondlinux/bin. Вызов сторонних утилит (например, «апплетов» Control Panel) осуществляется посредством специального протокола «exec:» (компонент KIO_EXEC, реализованный программистами Lycoris). Для обзора сети Windows или локальных дисков используются протоколы, включенные в состав KDE по умолчанию, такие как smb, file, devices. Лично мне подобное решение кажется весьма удачным, и я рекомендую разработчикам иметь его в виду при создании каких-либо утилит для KDE. Взаимосвязь Desktop/LX Control Panel с Konqueror имеет еще один неожиданный эффект. Работая с панелью управления, вы можете использовать вкладки (tabs), как и при просмотре обычных веб-страниц. Это позволяет более эффективно использовать рабочее пространство.
администрирование
Ðèñóíîê 2. Âñå ýòî – ïðîñòî HTML-ñòðàíèöû, îòêðûòûå â îêíå Konqueror. Êòî áû ìîã ïîäóìàòü?
Как и каждый уважающий себя настольный дистрибутив, Lycoris Desktop/LX 1.4 содержит «джентльменский минимум: Adobe Acrobat Reader, Macromedia Flash 7, Java Runtime Environment (JRE) 1.4 и RealPlayer 8. Все перечисленные продукты доступны в качестве подключаемых модулей к Lycoris Web Suite. Предыдущая версия дистрибутива включала также небольшое аудиоруководство, подобное тому, что поставляется вместе с Linspire, но сейчас оно кудато исчезло. Зато наряду со шрифтами семейства Bitstream Vera имеются также шрифты Bitstream Delta Hinted Fonts. Среди этого многообразия глифов можно отыскать и буквы кириллического алфавита (рис. 3). Официальной поддержки русского в Lycoris Desktop/LX, конечно, нет, однако программ, входящих в стандартный комплект поставки вполне достаточно для минимальной русификации на уровне оригинальных версий Knoppix. Для переключения раскладок можно использовать стандартные средства KDE.
Ðèñóíîê 3. Âñòðîåííûå ñðåäñòâà èíòåðíàöèîíàëèçàöèè ïîçâîëÿþò õóäî-áåäíî ïèñàòü íà ðîäíîì ÿçûêå
Совместимость с Windows обеспечивается офисным пакетом KOffice, в принципе умеющим читать и сохранять документы в форматах, поддерживаемых Microsoft Office (хотя OpenOffice.org справляется с этой задачей гораздо лучше) и эмулятором Wine. Предложение запустить после3
дний появляется автоматически, если вставить в привод CDROM диск с приложением Win32 (функция autorun) или попытаться запустить его (приложение) иным образом3. На практике у меня не получилось запустить в Wine ни одной программы. Возможно, это связано с тем, что эмулятор настроен на работу в системе с существующим Windowsразделом (или попросту не настроен). Для расширения возможностей дистрибутива существует репозитарий программ Iris Software Gallery (http:// iris.lycoris.com). Работа с ним осуществляется с помощью специального мастера, однако для этого необходим идентификатор Product ID (т.е. коммерческая лицензия на Desktop/LX). На сегодняшний день в Iris представлено чуть менее 400 (против 1900 в Linspire Click-n-Run Warehouse) пакетов, сгруппированных в 10 разделах. Здесь можно найти средства разработки (но не gcc, который, как мы помним, является частью Desktop/LX Deluxe), пакет русификации KDE, файловые менеджеры Midnight Commander и Krusader, HTML-редактор Bluefish и т. д. В отличие от все того же CNR, доступ к Iris бесплатен, если не считать стоимости Product ID и не ограничен по времени. Желающие могут также настроить систему под свои собственные нужды, установив необходимое ПО из обычных RPM-пакетов. Lycoris Desktop/LX позволяет удобно работать со съемными носителями информации. Компакт-диски, Flash-«брелки» и прочая «мелочь» автоматически распознаются и монтируются системой. К моему великому удивлению, я не нашел опции для отключения USB-носителей (размонтирование компакт-дисков происходит автоматически при попытке извлечь их из привода).
Провожают по... В заключение попробуем вывести «формулу Desktop/LX». Дистрибутив создает ощущение чего-то домашнего, столь часто встречающееся в любительских проектах и столь редкое в коммерческих решениях. Однако это не сказывается на качестве продукта, которое остается весьма высоким, хотя и не идеальным (вспомним про проблемы с загрузкой ядра, X Window System и Wine). По сравнению с альтернативными вариантами Lycoris Desktop/LX неплохо русифицирован, и мне даже приходилось слышать о его сторонниках, проживающих на территории РФ. К минусам системы можно отнести не слишком большой выбор доступного ПО (при существующем многообразии 400 наименований это почти капля в море) и отсутствие OpenOffice.org в стандартном комплекте поставки. Однако все эти недостатки так или иначе преодолимы, а цена на данный продукт не очень высока даже по отечественным меркам. Если вы не стремитесь иметь систему, которая бы думала за вас, имеете достаточный опыт работы с компьютером и всего лишь опасаетесь командной строки, попробуйте найти оценочную версию Desktop/LX. Быть может, вам понравится дистрибутив, рожденный прямо под носом у корпорации Microsoft? Автор выражает благодарность Шабунио Ю.А. за идеи, высказанные при написании данной статьи.
Кстати, чтобы открыть файл в Lycoris Desktop/LX, достаточно щелкнуть по нему мышью всего один раз. Это может показаться непривычным.
№1, январь 2005
11
администрирование
ПРОКСИ-СЕРВЕР OOPS: ПЕРВЫЕ ВПЕЧАТЛЕНИЯ
СЕРГЕЙ СУПРУНОВ Что такое прокси-сервер, пояснять, думаю, не требуется. Для UNIX-машин стандартом де факто является Squid. Проверенный временем, отлично документированный, мощный, он способен удовлетворить большинство запросов системных администраторов. Однако для моей сети, в которой
12
доступ в Интернет имеют не более десятка пользователей и особого контроля ни за трафиком, ни за правами доступа не требуется, он выглядел несколько избыточно. И вот после нескольких лет безупречной службы Squid был безжалостно деинсталлирован, и его место занял oops.
администрирование Установку на свой сервер (FreeBSD 5.3) я выполнял из портов с помощью утилиты portupgrade: # portupgrade oops
На этапе конфигурирования порта (см. рис. 1) нужно включить поддержку DB4 – она понадобится для работы с кэшем.
се с указанным IP-адресом, а не на всех имеющихся интерфейсах. Следующий полезный параметр – userid. Здесь нужно задать имя или UID пользователя, с правами которого будет работать oops. По умолчанию это пользователь oops. Если вы используете другого – не забудьте внести соответствующие изменения до инициализации базы кэша. Далее следуют параметры logfile, accesslog и pidfile. Установите те пути, которые у вас используются. Для лог-файлов попутно можно задать параметры ротации. В файл statistics (по умолчанию /var/run/oops/oops_ statfile) раз в минуту сбрасывается текущая статистика вида: clients uptime http_requests http_hits icp_requests req_rate hits_rate free_space
:7 : 181 sec. : 287 : 82 :0 : 2/s : 28% : 99%
Назначение указанных параметров перечислено в таблице: Ðèñóíîê 1
Нужный порт будет установлен при этом автоматически. Также можно включить поддержку MySQL или PostgreSQL для хранения базы авторизации. На вопрос о том, нужно ли создать пользователя oops, с правами которого будет работать прокси-сервер, был дан положительный ответ. В принципе можно использовать и существующего пользователя (например, nobody или оставшегося от Squid одноименного пользователя), главное – не забыть подправить конфигурацию. Скудный man oops слегка опечалил. Справедливости ради нужно заметить, что и squid в этом смысле далек от совершенства. Конфигурационный файл, по умолчанию /usr/ local/etc/oops/oops.cfg, документирован достаточно неплохо. Может быть, не так пространно и красиво, как Squid, но зато ориентироваться в нем оказалось проще. Для первого знакомства я решил настроить oops в простейшем варианте – кэширующий прокси-сервер без авторизации с возможностью ограничивать максимальную скорость соединения для клиента в зависимости от его IP-адреса. Переименовав oops.cfg.sample в oops.cfg, начинаем подстраивать его под свои нужды. Прежде всего нужно задать удобные для вас DNS-серверы в параметрах nameserver. Обычно вполне достаточно двух – основного, с которым будет идти работа, и резервного на всякий случай. Я просто продублировал то, что значится у меня в /etc/resolv.conf. Далее при желании можете изменить номер порта, на котором oops будет ожидать соединение – параметр http_port. По умолчанию используется 3128. Если у вас запущен Squid, то для тестирования oops можно поставить другой порт и тренироваться на нем. C помощью параметра bind, находящегося в этой же секции, можно заставить oops ожидать запросы на интерфей1
Вернемся к конфигурации. Параметры mem_max и lo_mark позволяют ограничивать количество оперативной памяти, потребляемой прокси-сервером. С помощью следующих далее опций start_red и refuse_at можно управлять количеством соединений, обслуживаемых одновременно. Первая из них указывает число соединений, при котором oops будет случайным образом «прореживать» очередь запросов, сбрасывая некоторые из них (так называемый алгоритм Early Drop). Если количество соединений все же достигнет определенного второй опцией, то все последующие запросы на соединение будут получать отказ. Остальное можно оставить как есть. Разве что может возникнуть желание поэкспериментировать с опцией force_ completion. По умолчанию она имеет значение 75, что означает продолжение загрузки объекта, загруженного более чем на 75%, даже если соединение с клиентом, запросившим объект, разорвется или клиент откажется от продолжения закачки. Далее следуют описания различных acl, которые можно рассматривать как переменные, используемые в дальнейшем. Для своей сети я ничего добавлять не стал – практически все, что мне нужно, оказалось удобнее описать непосредственно в секциях групп, о которых и пойдет речь ниже. Группу «paco», включенную по умолчанию (по крайней мере во FreeBSD), вполне можно рассматривать как пример – она содержит практически все параметры, которые могут быть использованы в настройках групп, и достаточно подробно прокомментирована. По умолчанию она обслу-
Например, ввод в адресной строке браузера адреса http://www.yandex.ru увеличит значение http_hits на 1 (запрошена одна страница), а http_requests увеличится при этом на 30-40, поскольку для каждого объекта, размещаемого во внешнем файле (рисунки, css, js-файлы и т. д.) формируется отдельный HTTP-запрос.
№1, январь 2005
13
администрирование живает подсети 195.114.128/19, 127/8 и 195.5.40.93/32 (см. параметр networks). Если случайно диапазон ваших адресов попадет в описанный для этой группы, то поменяйте этот параметр, чтобы данная группа оставалась исключительно демонстрационной. Хотя никто, конечно, не запрещает вам использовать ее (в конце концов, в файле oops.cfg.sample она останется неизменной) или, наоборот, вообще удалить. Но мне удобнее, когда подсказки всегда под рукой. Еще обратите внимание, что в эту группу попадает localhost. Как правило, обращений к прокси-серверу с локальной машины не происходит, но если вы решите проверить его работу, например, с помощью телнета «telnet localhost 3128», то должны понимать, что обслуживание запроса будет выполняться согласно правилам этой группы (если, конечно, вы не определите для localhost другую группу). Рассмотрим подробнее пару моих групп: group ourlan networks badports bandwidth per_ip_bw http { allow } }
{ 192.168.0.0/24; [0:79],110,138,139,513,[6000:6010] ; 16k; 4k; dstdomain * ;
group ouradmin { networks 192.168.0.25/32; badports [0:79],110,138,139,513,[6000:6010] ; http { allow dstdomain * ; } }
В группу ourlan попадут все IP-адреса из указанных в параметре networks, если они не попали в более узкие группы. Принадлежность адреса к группе определяется в порядке уменьшения маски. То есть адрес 192.168.0.25, формально попадающий и в группу ourlan, и в группу ouradmin, будет обслуживаться в соответствии с правилами группы ouradmin, несмотря на то что она описана позже. Помимо определения допустимых адресов, для всех машин локальной сети, кроме машины администратора, задано ограничение скорости: для всей группы доступная полоса ограничивается значением 16 Кб/с, и дополнительно для каждого клиента доступно не более 4 Кб/с. То есть в данном случае одновременно только 4 клиента смогут работать на максимально доступной им скорости. Если число клиентов возрастет, то доступные для всей группы 16 Кб/с будут делиться между ними поровну. Например, при одновременной работе 8 пользователей из этой группы каждому достанется по 2 Кб/с. При желании в секции http-группы можно более жестко установить доступ к конкретным доменам – либо перечислить разрешенные в параметре allow, либо разрешить все, но запретить доступ к некоторым с помощью параметра deny. Запрет или разрешение распространяется на сам указанный домен и все его поддомены. Например, параметр «deny narod.ru» запретит доступ ко всем «народным» файлам, а «allow ru» разрешит посещать только сайты в зоне «ru». Также поддерживается одиночный символ «*», означающий любые домены. Если домен попадает как в правило allow, так и в deny, применяется то, которое точнее описывает этот домен.
14
Например: http { }
denydstdomain ru ; allow dstdomain narod.ru ;
Эти правила запретят доступ ко всем доменам, кроме «народных». Если доменов, для которых вводятся те или иные ограничения, достаточно много, то удобно их вынести в отдельный файл (по одному в строке) и подключать его следующим образом: deny
dstdomain include:baddomains.lst ;
Более гибкое регулирование доступа обеспечивает механизм перенаправлений, который будет рассмотрен ниже. После секций групп следует секция storage, описывающая параметры файла, который будет использоваться для хранения кэша. В отличие от Squid, хранение кэшированных объектов в oops осуществляется в одном файле-хранилище, а не в отдельных файлах для каждого объекта. Это несколько разгружает систему, поскольку заботу о записи в кэш oops берет на себя, и по идее должно способствовать увеличению скорости работы, но на моих минимальных нагрузках это совершенно незаметно. С другой стороны, подобная схема ограничивает максимальный размер файла значением 2 Гб. Если вам требуются большие хранилища, соберите oops с поддержкой GigaBase. В принципе можно создать несколько хранилищ, используя нужное количество секций storage. Это может быть полезно для распределения базы по разным разделам жесткого диска, если размеры каждого из них не позволяют выделить желаемое место на одном разделе, а также для преодоления вышеупомянутого ограничения на размер файла. Поскольку при этом скорость работы с кэшем должна ненамного, но снижаться, старайтесь по возможности использовать один файл. Нужно заметить, что файлы-хранилища создаются во время инициализации, которой мы займемся немного позже, когда разберемся с конфигурацией. Процент занятости кэша можно контролировать в приведенном выше файле /var/run/oops/oops_statfile или с помощью управляющей утилиты oopsctl, которую мы скоро рассмотрим. Далее следуют секции модулей. Модуль lang позволяет задать параметры перекодировки и кодировку по умолчанию. Шаблон HTML-файла сообщения об ошибках можно описать в секции err, если хотите изменить вид, принятый по умолчанию. Файл-шаблон задает вид страницы с сообщением об ошибке, текст самого сообщения в процессе работы подставляется вместо переменных %M (на языке, указанном в параметре lang этой же секции) и %m (на английском языке). Последующие модули в большинстве своем отвечают за авторизацию. Oops поддерживает хранение базы авторизации в текстовом файле (формировать его следует с помощью утилиты htpasswd, входящей в состав Apache), в базах MySQL или PostgreSQL. Модуль redir позволяет задавать более гибкие условия
администрирование фильтрации трафика, чем правила deny и allow в группах. Помимо разрешения и запрета, запрос можно перенаправить на другой ресурс либо выполнить «внутреннюю» подстановку. В данной секции указывается полное имя файла, содержащего правила «редиректа» (параметр file) и шаблон сообщения о запрете доступа (параметр template). Файл правил (по умолчанию /usr/local/etc/oops/redir_rules) содержит правила в следующем формате: Ðåãóëÿðíîå_âûðàæåíèå
[Äåéñòâèå]
Регулярное выражение сопоставляется с адресом запрошенной страницы, и в случае соответствия по отношению к данному запросу может быть выполнено одно из следующих действий:
Если действие не указано, то пользователю возвращается страница «Просмотр страницы запрещен», созданная на основе шаблона, указанного в параметре template. «Внутренние» объекты компилируются вместе с oops. В версии 1.5.23 файл redir.c содержит следующее определение «внутренних» объектов: static internal_doc_t redir_internals[] = { {"nospam1x1", "image/gif", sizeof(nospam1x1gif), ↵ 3600, nospam1x1gif}, {"nospam468x60", "image/gif", sizeof(nospam468x60gif), ↵ 3600, nospam468x60gif}, {"nospam_close", "text/html", sizeof(nospam_close)-1, ↵ 3600, nospam_close}, {"nospam_empty", "text/html", sizeof(nospam_empty)-1, ↵ 3600, nospam_empty}, {"nospam_js", "application/x-javascript", ↵ sizeof(nospam_js)-1, 3600, nospam_js}, {""} };
В этом же файле определяются и сами объекты. Например, перенаправление «internal:nospam_close» вернет клиенту такую HTML-страницу вместо запрошенной: <html></html><SCRIPT LANGUAGE="JavaScript"> ↵ <!--window.close()//--></SCRIPT>
Регулярные выражения строятся по стандартным для UNIX правилам. Ниже дан пример файла redir_rules, демонстрирующий некоторые особенности: # Åñëè çàïðîñ ñîîòâåòñòâóåò íåñêîëüêèì ïðàâèëàì, # ïðèìåíÿåòñÿ ïåðâîå (íà microsoft.com ìû ïîïàñòü íå ñìîæåì) .*soft.* .*micro.* allow # Çàïðåùàåì äîñòóï íà âñå äîìåíû òðåòüåãî óðîâíÿ, èìÿ # êîòîðûõ ñîäåðæèò ñòðîêó amsand, çà èñêëþ÷åíèåì amsand.narod.ru http://.*amsand.narod.ru allow http://.*amsand\..+.ru # Ïðîâåðêà ðàáîòû «âíóòðåííèõ» ïåðåíàïðàâëåíèé http://.*/.*test1x1.* internal:nospam1x1 http://.*/.*test468x60.* internal:nospam468x60 http://.*/.*test_close.* internal:nospam_close http://.*/.*test_empty.* internal:nospam_empty http://.*/.*test_js.* internal:nospam_js # Ëþáîé çàïðîñ, ñîäåðæàùèé â èìåíè ðåñóðñà óïîìèíàíèå # Àëüòàâèñòû, áóäåò ïåðåíàïðàâëåí íà ñòàðòîâóþ ñòðàíèöó
№1, январь 2005
# ßíäåêñà (êñòàòè, âû äàæå íå ñìîæåòå âûïîëíèòü ïîèñê â òîì æå # ßíäåêñå ïî çàïðîñó «altavista.com», ïîñêîëüêó â ðåçóëüòàòå # áóäåò îòïðàâëåí çàïðîñ # «http://www.yandex.ru/yandsearch?rpt=rad&text=altavista.com», # êîòîðûé òàê æå áóäåò ñîîòâåòñòâîâàòü äàííîìó ïðàâèëó) altavista.com http://yandex.ru # Ïåðåíàïðàâëÿåò íà ya.ru âñå çàïðîñû, èìåþùèå öèôðû â ÷àñòè # èìåíè, ñîîòâåòâòóþùåé äîìåíó 3-ãî óðîâíÿ, íàïðèìåð: # http://www.max2.dom.ru/ # http://www3.w3c.org/index.html http://.*[[:digit:]]+.*\.[[:alnum:]]+\.[a-z]{2,4}/.* ya.ru #  îòâåò íà ëþáîé çàïðîñ, çàâåðøàþùèéñÿ ñèìâîëàìè shtml, # áóäåò âîçâðàùåíà ïóñòàÿ ñòðàíèöà (ñîäåðæèò òîëüêî òåã <br>) shtml$ internal:nospam_empty # Áóäåò çàïðåùåí äîñòóï ê ëþáîìó ðåñóðñó, àäðåñ êîòîðîãî # çàêàí÷èâàåòñÿ èìåíåì ôàéëà page ñ îäíèì èç ïåðå÷èñëåííûõ # ðàñøèðåíèé http://.*/page.(html|htm|phtml)$ # Çàïðåùàåì äîñòóï êî âñåì ñàéòàì â çîíå com, äîìåííîå èìÿ # êîòîðûõ èìååò äëèíó 7-9 ñèìâîëîâ (3-5 ïëþñ ".com") è äëÿ # êîòîðûõ íå óêàçàíî èìÿ êîíêðåòíîãî ôàéëà èëè ïàïêè, # íàïðèìåð: http://qwer.com/ http://.{3,5}\.com/?$
За пояснениями синтаксиса регулярных выражений можно обратиться, например, к странице справочного руководства man grep(1), к разделу «REGULAR EXPRESSIONS». Приведенные выше правила на практике бесполезны, зато хорошо демонстрируют различные возможности. Ниже приводится более полезный файл: # Çàïðîñ ê ßíäåêñó áóäåò ïåðåíàïðàâëåí íà «àñêåòè÷íûé ïîèñê», # ÷òî ìîæíî èñïîëüçîâàòü äëÿ ñíèæåíèÿ òðàôèêà, ñîçäàâàåìîãî # ïîëüçîâàòåëÿìè http://(www.)?yandex\.ru/?$ http://ya.ru # Áëîêèðóåì âñå çàïðîñû ñî ñëîâîì porno, â òîì ÷èñëå # è ôîðìèðóåìûå ïîèñêîâèêàìè porno # Âìåñòî ëþáûõ èçîáðàæåíèé âîçâðàùàåì «ïóñòîé» ðèñóíîê (gif|jpg|jpe|jpeg)$ internal:nospam1x1
Любые изменения в файлах правил «подхватываются на лету», не требуя перезапуска сервера. Ну и чтобы указанные правила распространялись на конкретную группу, в секции этой группы нужно указать опцию redir_mods со значением «redir». Oops позволяет создавать до 15 дополнительных наборов правил перенаправления, которые описываются в модулях с redir/1 по redir/15 с таким же синтаксисом, что и redir, и могут быть назначены той или иной группе указанием имени модуля в строке redir_mods. Чтобы oops работал как прозрачный прокси-сервер, дополнительно нужно раскомментировать секцию «module transparent», и в секциях тех групп, которым будет позволено пользоваться его благами, нужно в параметр redir_mods добавить значение «transparent». Ну и не забыть выполнить перенаправление трафика в правилах firewall, например, так: # ipfw add 1000 fwd localhost,3128 ↵ ip from 192.168.0.0/24 to any dst-port 80
Работа в режиме прозрачного прокси-сервера позволяет клиентам вообще ничего не знать о посреднике на пути к запрошенному сайту. Браузер просто формирует стандартный запрос на 80-й порт и получает ответ. Естественно, что в таком режиме речь об авторизации уже не идет – браузер просто не подозревает, что в этом может возникнуть необходимость. Подробнее вопросы авторизации и рабо-
15
администрирование ты сервера в прозрачном режиме были освещены в статье Дмитрия Репина «Transparent proxy. Быть или не быть?», журнал «Системный администратор», №4, апрель 2004 г. Настало время выполнить инициализацию кэш-хранилища: # oops –c /usr/local/etc/oops/oops.cfg –z
После непродолжительной работы появятся файлы, описанные в секциях storage. Осталось запустить oops и убедиться, что все работает как нужно. Для управления лучше всего использовать утилиту oopsctl:
Остановка сервера выполняется командой: # oopsctl stop
Чтобы применить изменения, внесенные в конфигурационный файл, используется следующая команда: # oopsctl reconfigure
Все ключи запуска можно посмотреть в man oopsctl или по команде: # oopsctl help
# oopsctl start
Прописываем адрес и порт нашего proxy в настройках браузера (если прокси-сервер непрозрачный) и проверяем работоспособность. Во время работы будут меняться параметры статистики (см. /var/run/oops/oops_statfile). Более полную информацию можно просмотреть, выполнив следующую команду:
Вот вроде бы и все. Еще осталось позволить oops загружаться при старте системы, для чего файл /usr/local/etc/ rc.d/oops.sh.sample нужно переименовать в oops.sh. В заключение отмечу, что формат access-файла oops совместим с форматом Squid, и для его анализа подойдет любой анализатор, разработанный для Squid. Мои запросы и в этом плане минимальны, поэтому я использую простой сценарий на Python:
# oopsctl stat ## -- General info -Version : 1.5.23 Uptime : 5646sec, (0day(s), 1hour(s), 34min(s)) Last update : Fri Dec 17 16:03:54 2004 Clients : 1 (max: 8) HTTP requests: 415 ICP requests: 0 Total hits : 96 Curr.req.rate: 0,00 req/sec (max: 2,68) Tot.req.rate : 0,07 req/sec Curr.hit.rate: 0,00 % Tot.hit.rate : 23,13 % Curr.icp.rate: 0,00 req/sec (max: 0,00) ## -CPU -Total usage : 22607ms Delta usage : 195ms Delta time : 61000ms
Delta usage показывает использование процессора за последний Delta time. То есть в данном случае за последнюю 61 секунду было использовано 195 мс процессорного времени. Если говорить точнее, то эти цифры показывают, что предыдущий замер делался 61 секунду назад, и с тех пор общее время использования процессора (total usage) выросло на 195 мс. Собственно, на основе этих данных и считается Curr. CPU: 195/61000*100 = 0.32%. Curr. CPU : 0,32 % (0,03s+0,29u) Aver. CPU : 0,40 % (0,11s+0,29u) ## -- storages -Disks msg : Cleanup finished Storage : /var/oops/storage/oops_storage0 Size : 200,00 MB Free blks : 51197 blks (199,99Mb) 99,99 % State : READY Fileno :7 Storage : /var/oops/storage/oops_storage1 Size : 200,00 MB Free blks : 51197 blks (199,99Mb) 99,99 % State : READY Fileno :9 ## -- end of storages -## -- modules -. . . пропущено . . . ## -- end of modules -## -- icp peers -## -- end of icp peers--
16
#!/usr/local/bin/python import sys try: logfile = sys.argv[1] except: logfile = 'access.log' logs = open(logfile, 'r').readlines() traffic = {} counter = {} for log in logs: splitted = log.split() ip = splitted[2] if traffic.has_key(ip): traffic[ip] = traffic[ip] + int(splitted[4]) counter[ip] = counter[ip] + 1 else: traffic[ip] = int(splitted[4]) counter[ip] = 1 keys = traffic.keys() keys.sort() for ip in keys: print '%s | %7d | %15d (%7.2f) |' % (ip.ljust(18), ↵ counter[ip], traffic[ip], traffic[ip] / 1048576.0)
Результат выглядит примерно так (для каждого IP возвращается количество сессий и суммарный трафик в байтах и мегабайтах): # ./getstat 10.0.0.203 10.0.0.207 127.0.0.1 192.168.0.8 66.32.79.217
| 749 | 4523870 (4.31) | | 1| 1123 (0.00) | | 1| 1298 (0.00) | | 234 | 2871338 (2.74) | | 2| 0 (0.00) |
На данный момент я вполне доволен как возможностями oops, так и гибкостью и понятностью его конфигурационных файлов. Как он будет вести себя в дальнейшем, когда потребуется что-то экзотическое – посмотрим. Дополнительную информацию и сам oops можно получить на сайте проекта: www.oops-cache.org.
администрирование
ПРОГРАММНОЕ УПРАВЛЕНИЕ ФАЙЛОВОЙ СИСТЕМОЙ С ПОМОЩЬЮ VBScript ИВАН КОРОБКО
Создавая сценарии, позволяющие автоматизировать различные процессы в сети, зачастую необходимо программно управлять файловой системой NTFS, а именно: создавать, удалять, перемещать, копировать файлы и папки; изменять их атрибуты и права доступа к ним. Такие сценарии могут быть созданы с помощью VBScript или JSсript. В данной статье все примеры будут приведены на VBScript.
Основы программного управления файловой системой Для программного управления файловой системой NTFS с помощью VBScript рекомендуется использовать встроенный объект FileSystem Object, поддерживающий набор методов, перечисленных в таблице 1: Òàáëèöà 1
где path – путь к каталогу, например, «C:\FolderName» или «\\Server\ShareName». В качестве обработчика ошибок рекомендуется использовать функцию FolderExists(), с помощью которой можно определить существует ли каталог, по указанному пути: path="…" Set fso=WScript.CreateObject("Scripting.FileSystemObject") If fso.FolderExists(path) then Set oFolders=fso.GetFolder(path) … Else MsgBox "Folder " + path + " Not Exists" End If
Определение списка подпапок в указанной директории Формирование списка осуществляется с помощью свойства Name набора SubFolders и Files. С помощью набора SubFolders определяется список папок, вложенных в указанный каталог, а с помощью Files – соответственно список файлов. Приведем пример, в котором будет определены подпапки каталога Windows:
Для получения доступа к объектам FSO необходимо создать переменную-объект и присвоить ей ссылку на объект FileSystemObject:
path="C:\Windows" Temp="" Set fso=WScript.CreateObject("Scripting.FileSystemObject") If fso.FolderExists(path) then Set oFolders=fso.GetFolder(path) Set OSubFolders=oFolders.Subfolders For each i In OSubFolders Temp=Temp+i.Name+chr(13) Next Else Temp= "Folder " + path + " Not Exists" End If MsgBox Temp
Set fso=WScript.CreateObject(“Scripting.FileSystemObject”)
После создания объекта становятся доступны его методы, свойства и дочерние объекты. Поскольку в данной статье будут рассмотрены вопросы, касающиеся операций с файлами и папками, то некоторые объекты и наборы, такие как Drive(s) и TextStream, не будут рассмотрены.
Программное получение доступа к папкам С помощью набора Folders осуществляется формирование списка вложенных файлов и папок в указанном каталоге; просмотр атрибутов каталога; создание, перемещение, переименование и удаление папок. Доступ к набору Folders можно получить, воспользовавшись следующим шаблоном: path="…" Set fso=WScript.CreateObject("Scripting.FileSystemObject") Set oFolders=fso.GetFolder(path) 1
Определение списка всех вложенных подпапок в каталоге Для чтения всей структуры подкаталогов необходимо вышеописанный механизм поместить в функцию и сделать ее рекурсивной1. Функция будет иметь два параметра – путь к абсолютному подкаталогу (PATH) и уровень вложенности подкаталогов (IDX). Данные, содержащие абсолютные пути к подкаталогам, разумно записывать в динамический одномерный массив. Приведем пример создания и заполнения элементов динамического массива на примере чтения структуры подкаталогов, затем приведем шаблон рекурсивной функции. Path="C:\RootFolder" i=0 Dim Array() 'Îáúÿâëåíèå äèíàìè÷åñêîãî ìàññèâà Set fso=Wscript.CreateObject("Scripting.FileSystemObject")
Рекурсивная функция – это функция, вызывающая саму себя, при этом она обязательно передает параметры. Рекурсивные функции, как и правила, используются для чтения иерархической структуры.
№1, январь 2005
17
администрирование Set oFolder=fso.GetFolder(path) Set oFolders=oFolder.SubFolders ' Èçìåíåíèå ðàçìåðà äèíàìè÷åñêîãî ìàññèâà Redim Preserve Array(oFolders.count) For Each of In oFolders Array(i)=cstr(oF.Path) ' Çàïèñü ýëåìåíòîâ â ìàññèâ i=i+1 Next '×òåíèå ýëåìåíòîâ ìàññèâà: Temp="" For i=Lbound(Array) to Ubound(Array) Temp=Temp+cstr(Array(i))+chr(13)+chr(10) Next MsgBox Temp
Шаблон рекурсивной функции: ……….. ' Âûçîâ ôóíêöèè RecFolder â òåëå ñöåíàðèÿ RecFolder index, path ……….. Function Recfolder (idx, path) ……….. ……….. ……….. Call Recfolder (idx+1, path) ……….. End Function
На основе изложенного материала приведем листинг скрипта, который позволяет определить названия всех подпапок, вложенных в указанный каталог (в примере – переменная path): dim path_array() path="c:\windows" i=0 temp="" detect(q) MsgBox "oFolders_count: "+cstr(detect(q)) For j=0 to cstr(ubound(path_array)-1) path=cstr(path_array(j)) temp=temp+cstr(j)+": "+path+chr(13) Next MsgBox temp Function detect(c) i=0 Set fso=Wscript.CreateObject("Scripting.FileSystemObject") Set oFolder=fso.GetFolder(path) Set oFolders=oFolder.SubFolders Redim Preserve path_array(oFolders.count) detect=oFolders.count For Each oF In oFolders path_array(i)=path+"\"+cstr(oF.Name) i=i+1 Next End Function
Определение списка файлов, находящихся в директории Методика определения списка файлов, содержащихся в директории, та же, что и в случае определения списка подкаталогов. Разница заключается в том, что вызывается набор Files, а не SubFolder: path="c:\windows" Set WSHShell = WScript.CreateObject("WScript.Shell") Set fso=createobject("Scripting.filesystemobject") Set oFolder=fso.GetFolder(path) Set oFiles=oFolder.files MsgBox "oFiles_count: "+cstr(oFiles.count) temp="" For each oFile in oFiles temp=temp & oFile.name & chr(13) Next MsgBox text
18
Управление атрибутами файлов Каждый файл имеет набор параметров, которые его характеризуют – название, расширение, размер, даты создания и последнего изменения файла, его атрибуты. О том, как считывать названия файлов и их расширения, было рассказано ранее. Пришло время рассказать о методике чтения дат и атрибутов файлов.
Определение атрибутов файлов Получив доступ к файлам, как это показано в предыдущем разделе, с помощью свойства Attributes можно определить атрибуты файлов. Свойство Attributes возвращает двоичное значение, расшифровка которых приведена в таблице: Òàáëèöà 2
Приведем пример чтения атрибута файла boot.ini: path="c:\boot.ini" Set WSHShell = WScript.CreateObject("WScript.Shell") Set fso=createobject("Scripting.filesystemobject") Set oFile=fso.GetFile(path) MsgBox oFile.Name&": "& oFile.Attributes
Если атрибуты этого файла никто не изменял, то значение свойства oFile.Attributes будет равно 39, что в соответствии с таблицей обозначает, что boot.ini имеет следующие атрибуты: только для чтения, скрытый, системный, архивный. Для того чтобы пользователь каждый раз не занимался определением атрибутов файлов, необходимо использовать функцию, с помощью которой будет осуществляться сопоставление кода, возвращаемого функцией атрибутам. Также необходимо осуществлять проверку на существование файла с помощью функции FileExists(): path="c:\boot.ini" Set WSHShell = WScript.CreateObject("WScript.Shell") Set fso=createobject("Scripting.filesystemobject") if fso.FileExists(path) then Set oFile=fso.GetFile(path) Attr_value=oFile.Attributes temp=A_detect() MsgBox oFile.Name&": "& temp else MggBox "Ôàéë " &path& " íå ñóùåñòâóåò" end if function A_detect() t="" if (Attr_value and &H01)> 0 Then ↵ t=t+"Òîëüêî äëÿ ÷òåíèÿ; " if (Attr_value and &H02)> 0 Then ↵ t=t+"Ñêðûòûé; " if (Attr_value and &H04)> 0 Then ↵ t=t+"Ñèñòåìíûé; " if (Attr_value and &H20)> 0 Then ↵ t=t+"Àðõèâíûé; " if (Attr_value and &H800)> 0 Then ↵ t=t+"Ñæàòûé; " A_detect=t end function
администрирование Изменение атрибутов файлов Изменение атрибутов файлов с помощью FSO осуществляется присвоением другого значения переменной oFile.Name. Значение может быть присвоено как в шестнадцатеричном, так и в десятеричном виде в (см. таблицу 2): path="c:\readme.txt" Set WSHShell = WScript.CreateObject("WScript.Shell") Set fso=createobject("Scripting.filesystemobject") Set oFile=fso.GetFile(path) MsgBox oFile.Name&": "& oFile.Attributes oFile.Attributes=39 MsgBox oFile.Name&": "& oFile.Attributes
По умолчанию вновь созданный файл readme.txt имеет атрибут «Архивный»(32). Присвоив параметру oFile.Attributes значение 39, файлу будут назначены следующие атрибуты: только чтение, скрытый, системный, архивный.
Операции над файлами и папками Над файлами и папками можно производить следующие операции: создание, копирование, перемещение, удаление. Сначала опишем операции, выполняемые с папками, затем файлами.
Source – обязательный параметр, в котором передается строка с именем исходной папки (путем); путь может включать знаки подстановки, такие как «?» или «*». Рекомендуется использовать знаки подстановки для копирования или перемещения нескольких папок, одновременно удовлетворяющих заданному шаблону Destination – обязательный параметр, задающий путь к папке назначения в виде строки. Значение этого параметра не может содержать символов подстановки. В том случае если путь заканчивается «\» и папка-приемник не существует, то она будет создана. Overwrite – необязательный параметр, который принимает значение False(0) или True(1). Если он равен True, т.е. 1 (по умолчанию), то целевая папка будет перезаписана. Обратите внимание на то, что параметры указываются без скобок. Приведем примеры копирования и перемещения папок. Копирование папки: OldPath="C:\TempFolderOld" NewPath="C:\TempFolderNew" Set fso=WScript.CreateObject("Scripting.FileSystemObject") fso.CopyFolder OldPath, NewPath, 1 MsgBox "Ïàïêà " + OldPath + " ñêîïèðîâàíà â " + NewPath
Удаление папки:
Создание и удаление папок Создание и удаление каталогов осуществляется с помощью методов CreateFolder(path) и DeleteFolder(path) объекта FSO. Параметром каждого из этих методов является путь к каталогу – path. Используя эти методы, желательно включать в листинг скрипта обработчик ошибок, который проверяет наличие или отсутствие папки перед осуществлением какихлибо манипуляций с ней. Приведем два примера: первым из них проиллюстрируем процесс создания новой папки C:\TempFolder; во втором – процесс удаления этой папки. path="C:\TempFolder" Temp="" Set fso=WScript.CreateObject("Scripting.FileSystemObject") If fso.FolderExists(path)=0 then fso.CreateFolder(path) Temp= "Folder " + path + " Created " Else Temp= "Folder " + path + " Already Exists" End If MsgBox Temp
Удаление папки: path="C:\TempFolder" Temp="" Set fso=WScript.CreateObject("Scripting.FileSystemObject") If fso.FolderExists(path)<>0 then fso.DeleteFolder(path) Temp= "Folder " + path + " Deleted" Else Temp= "Folder " + path + " is Absent " End If MsgBox Temp
OldPath="C:\TempFolderOld" NewPath="C:\TempFolderNew" Set fso=WScript.CreateObject("Scripting.FileSystemObject") fso.MoveFolder OldPath, NewPath, 1 MsgBox "Ïàïêà " + OldPath + " ïåðåìåùåíà â " + NewPath
Копирование и перемещение файлов Копирование и перемещение файлов осуществляются с помощью методов Copy и Move соответственно. Поскольку использование этих методов одинаково, то они будут рассмотрены совместно. Шаблон вызова любого метода следующий: PathOld="C:\Folder\FileNameOld" PathNew="C:\Folder\FileNameNew" Set fso=WScript.CreateObject("Scripting.FileSystemObject") If (fso.FileExistes(PathOld)) Then Set oFile=fso.GetFile(PathOld) oFile.**** PathNew End If
где вместо «****» указывается название метода. Различие в использовании методов заключается в том, что при вызове метода Move после копирования файла осуществляется удаление первоисточника. Приведем пример копирования файла: PathOld="C:\Folder\1.txt" PathNew="C:\Folder\2.txt" Set fso=WScript.CreateObject("Scripting.FileSystemObject") If (fso.FileExistes(PathOld)) Then Set oFile=fso.GetFile(PathOld) oFile.Copy PathNew End If
Переименование, копирование и перемещение папок
Удаление файлов
Копирование папок осуществляется с помощью метода CopyFolder source, destination, overwrite, перемещение и переименование – с помощью MoveFolder source, destination, overwrite. Каждый их этих методов имеет три параметра:
Удаление файла осуществляется с помощью метода Delete, вызываемого аналогичным способом. Отличается лишь синтаксис самого метода: у метода Delete, в отличие от Copy или Move, отсутствуют параметры:
№1, январь 2005
19
администрирование PathDel="C:\Folder\1.txt" Set fso=WScript.CreateObject("Scripting.FileSystemObject") If (fso.FileExistes(PathDel)) Then Set oFile=fso.GetFile(PathDel) oFile.Delete End If
Параметр AccessMask (см. рис. 1): Òàáëèöà 4
Управление правами доступа на файлы и папки Создавая новую папку или файл на жестком диске с файловой системой NTFS, новому объекту присваиваются права доступа по определенным правилам. Если разговор идет о создании общих папок на сервере, то системного администратора, как правило, не устроят права доступа, назначаемые по умолчанию: они должны быть изменены в соответствии с определенными правилами, описываемыми шаблоном. О том, как программно изменить права доступа на папки и файлы, и пойдет разговор в следующем разделе.
Библиотека ADsSequrity.dll Программное управление правами доступа к файлам и папкам можно реализовать с помощью библиотеки ADs Sequrity.dll, входящей в комплект поставки ADSI Resource Kit (http://www.microsoft.com). Перед использованием библиотеки ее необходимо зарегистрировать на компьютере, на котором будет запускаться сценарий. Команда регистрации библиотеки выглядит следующим образом: Параметр AccessFlags (см. рис. 2): regsvr32.exe /s ADsSequrity.dll
Òàáëèöà 5
Доступ к вышеуказанной библиотеке осуществляется с помощью функции CreateObject(«ADsSecurity») по следующему сценарию: Set sec = CreateObject("ADsSecurity") Set sd = sec.GetSecurityDescriptor("FILE://c:\folder") Set dacl = sd.DiscretionaryAcl For Each ace In dacl Wscript.Echo cstr(ace.Trustee)+" " + cstr(ace.AccessMask) + ↵ " " + cstr(ace.AceType) + chr(13)+chr(10) Next Wscript.Echo dacl.AceCount
Как видно из примера, для управления правами необходимо создать новый экземпляр объекта ADsSecurity и указать к нему путь, который является параметром функции GetSecurityDescriptor(). Таким образом, можно получить доступ к коллекции DiscretionaryAcl, членами которой являются Trustee, AccessMask, AceType, AceCount и не фигурирующий в данном шаблоне RemoveAcl: Òàáëèöà 3
После многочисленных экспериментов были установлены и сведены в таблицы значения различных параметров:
20
Параметр AceType (см. рис. 1, 3): Òàáëèöà 6
Также приведем таблицу, в которой описан набор стандартных атрибутов (см. рис. 3): Òàáëèöà 7
администрирование Set sec = CreateObject("ADsSecurity") Set sd = sec.GetSecurityDescriptor("FILE://c:\Folder") Set dacl = sd.DiscretionaryAcl Set ace = CreateObject("AccessControlEntry") ace.Trustee = "Domain\Administrator" ace.AccessMask = &h20000000 ace.AceType = &h0 ace.AceFlags = &h3 dacl.AddAce ace1 sd.DiscretionaryAcl = dacl sec.SetSecurityDescriptor sd set dacl=nothing set sec=nothing
Если необходимо добавить сразу несколько новых объектов, то необходимо учесть некоторые нюансы, о которых скажем несколько слов после примера:
Ðèñóíîê 1
Set sec = CreateObject("ADsSecurity") Set sd = sec.GetSecurityDescriptor("FILE://c:\Folder") Set dacl = sd.DiscretionaryAcl Set ace1 = CreateObject("AccessControlEntry") ace1.Trustee = "msk\corwin" ace1.AccessMask = &h20000000 ace1.AceType = &h0 ace1.AceFlags = &h3 dacl.AddAce ace1 for i=0 to 10000000 next Set ace2 = CreateObject("AccessControlEntry") ace2.Trustee = "msk\sneretin" ace2.AccessMask = &h20000000 ace2.AceType = &h0 ace2.AceFlags = &h3 dacl.AddAce ace2 sd.DiscretionaryAcl = dacl sec.SetSecurityDescriptor sd set dacl=nothing set sec=nothing
Изучив пример, можно обнаружить две особенности:
! Для каждого нового добавляемого объекта необходимо
Ðèñóíîê 2
создать свой собственный объект AccessControlEntry, при этом описание объекта GetSecurityDescriptor и ADsSecurity у них может быть общим. ! После добавления нового объекта должно пройти некоторое время (особенно если сценарий находится на одном сервере, a объект, права доступа на который необходимо изменить, на другом), прежде чем он станет доступен для последующих действий. Для этого необходимо сделать в сценарии паузу. Поскольку в VBScript не существует такой функции, то предлагается вставить пустой цикл For…Next, на выполнение которого требуется определенное время.
Удаление существующих объектов Удаление существующих групп или пользователей осуществляется с помощью свойства RemoveAcl коллекции объектов DiscretionaryAcl.
Ðèñóíîê 3
Добавление новых объектов В качестве новых объектов могут выступать пользователи или группы. Приведем пример добавления нового пользователя:
№1, январь 2005
Set sec = CreateObject("ADsSecurity") Set sd = sec.GetSecurityDescriptor("FILE://c:\2") Set dacl = sd.DiscretionaryAcl For Each ace In dacl If (ace.Trustee="EveryOne") dacl.RemoveAce ace end if Next sd.DiscretionaryAcl = dacl set dacl=nothing set sec=nothing
Рассмотрев основы управления NTFS, читатель может приступить к реализации более сложных задач.
21
администрирование
HOTSPOT – ЭТО ПРОСТО!
АНДРЕЙ ПЛАТОНОВ С ростом популярности беспроводных сетей 802.11 a/b/g, объединённых общим названием Wi-Fi, всё быстрее развивается новое направление на рынке организации услуг доступа в Интернет – создание публичных зон доступа, или HOTSPOT. HOTSPOT – это место, где имеется доступ к беспроводной сети. И если с беспроводной составляющей HOTSPOT (имеются в виду точки доступа) всё более-менее понятно, то со средствами учёта и контроля пользователей по-прежнему возникают затруднения. Для разрешения этой проблемы многие производители сетевого оборудования приступили к выпуску специализированного оборудования для формирующегося рынка услуг. Не стала исключением и компания D-Link, представив шлюз для создания зон коллективного доступа в Интернет DSA-3100 и чекпринтер DSA-3100P. Итак, какие же функции должна выполнять система, на которой базируется HOTSPOT? ! Быстрое добавление пользователя в систему. ! Аутентификация пользователя. ! Подсчет трафика или времени, проведенного в сети. ! Автоматическое отключение пользователя при достижении лимита трафика или времени. Безусловно, эти функции можно реализовать даже на маломощной машине под управлением *nix. Однако D-Link обещает нам решение этих задач при помощи простого в настройке шлюза, который сможет настроить даже среднестатистический пользователь. Кроме того, шлюз будет интересен и более подготовленным пользователям, т.к. на его основе возможно построение полноценной биллинговой системы. Устройство имеет три порта Ethernet: ! WAN-порт – для подключения к сети Интернет. ! LАN-порт (частная сеть) – подключаются клиенты, для которых не требуется аутентификация (например, локальная сеть кафе, в котором организован HOTSPOT). ! Authentication-порт – к этому порту подключается сеть, клиенты которой будут проходить аутентификацию перед выходом в Интернет. На базе шлюза можно создать несколько типов хотспотов. Во-первых, это простейший случай – отдельно стоящий хотспот, в котором есть оператор. Такой хотспот организовывается довольно легко: нужна минимальная настройка
22
шлюза, с которой справится любой человек, имеющий базовые знания по IP-сетям. Все настройки осуществляются через встроенный веб-интерфейс. Оператор хотспота (человек, пробивающий чеки на тикет-принтере) также не будет загружен сложной работой. Добавление нового пользователя происходит очень просто: в меню вводится количество предоплаченных клиентом часов и нажимается кнопка «Print» на чек-принтере. В распечатанной карточке доступа (которая, правда, больше похожа на чек) находится вся необходимая для подключения к сети информация: ключ WEP-шифрования, логин и пароль для авторизации. При первой попытке пользователя обратиться к ресурсам Интернета он перенаправляется на веб-страницу авторизации. Обмен авторизационной информацией происходит по протоколу HTTPS, что повышает безопасность системы. На случай, если браузер клиента не поддерживает защищённое SSL-соединение (что бывает крайне редко), предусмотрена возможность использования открытого HTTP. Методика авторизации пользователей, построенная на базе Web, избавляет менеджера HOTSPOT от хлопот по установке и настройке на машинах пользователей дополнительного клиентского ПО, управляющего авторизацией. К вышеописанному виду относится большинство HOTSPOT, которые создаются в аэропортах, на вокзалах, в выставочных комплексах и гостиницах. В них по обыкновению используется тарификация по времени на условиях предоплаты. Шлюз D-Link DSA-3100 в паре с принтером DSA-3100P идеально подходят для решения подобных задач – HOTSPOT может быть развернут всего за несколько часов (в зависимости от масштабов) даже силами приходящего админа или просто продвинутого пользователя. Кроме простейших случаев, существуют более сложные варианты – например, когда мы имеем не один, а целую сеть HOTSPOT, причём необязательно в каждом из них есть оператор, принимающий платежи. Возможен, например, такой вариант: клиент активирует карточки предоплаты (скретч-карты) для зачисления денег на свой электронный счёт. В этом случае шлюз DSA-3100 становится большой важной шестерёнкой под названием NAS (Network Access Server) в сложном механизме биллинговой системы. Аутентификация/Авторизация/Аккаунтинг (ААА) при этом проводятся через RADIUS-сервер. Ещё одним важным свойством такой системы является то, что для того, чтобы она стала полноценным биллингом,
на правах рекламы её, скорее всего, придётся немного доработать, что могут осуществить только самые упорные и опытные. Но не боги горшки обжигают!
RADIUS расшифровывается как Remote Authentication Dial In User Service. Изначально данный протокол был создан для обслуживания больших модемных пулов, но реализация получилась настолько удачной, что сейчас он часто используется не только для DialUP, но и для IP-телефонии, организации доступа в VPN-сети. Итак, раз заголовок нашей статьи «HOTSPOT – это просто!», мы рассмотрим самый простой вариант из всех возможных сложных вариантов и набросаем в общих чертах хотспотный биллинг, который и есть самое главное в хотспоте. Средством сбора статистики будут шлюзы DSA-3100. Несмотря на взрывной рост популярности Linux-систем, наиболее распространенной и знакомой для большинства остается Windows. Поэтому мы рассматриваем RADIUSсервер именно на его основе. Безусловно, для опытного юниксоида не будет проблемой связать DSA-3100, например, с freeradius, одним из важнейших достоинств которого является его бесплатность. Для эксперимента мы использовали компьютер под управлением Win2k Server и WinRadius 2.11 (http://www.it consult2000.com), как и большинство программ под Windows, WinRadius небесплатен, однако эту проблему можно решить тем или иным способом (например, купить ее). Теперь более подробно о том, как будет выглядеть наша учётно-биллинговая система и как она будет работать. Предположим, у нас есть некоторая опорная сеть, к которой через DSA-3100 подключены все наши хотспоты. Шлюз каждого хотспота настроен на работу с RADIUS, который в свою очередь взаимодействует с базой данных (в нашем случае это будет msAcsess – как самый простейший вариант), в которой хранятся учётные записи пользователей и в которую будет складываться статистика. Итак, проделаем следующее: ! поставим WinRadius; ! настроим WinRadius на взаимодействие с DSA-3100 и БД MSAccess; ! создадим пользователя на сервере RADIUS; ! аутентифицируемся и посчитаем трафик (посмотрим, как это всё записалось в БД); ! сделаем маленький веб-интерфейс к биллинговой системе, реализующий некоторый функционал.
№1, январь 2005
Настройка WinRadius
Настраиваем драйвер базы данных ODBC Это требуется для работы нашего RADIUS с БД MSAccess (файл базы данных есть в дистрибутиве WinRadius – WinRadius.mdb). ODBC – это аббревиатура от Open DataBase Connectivity (примерный перевод – открытая система связи с базами данных) – некий универсальный интерфейс к различным базам данных. Что-то вроде прослойки между пользовательскими приложениями и базами данных, которая позволяет скрыть особенности той или иной БД и унифицировать свойства всех источников данных.
23
администрирование
! В поле «Data Source Name» вписываем «WinRadius». ! В поле «Description» пишем что хотим. ! Нажимаем «Select», ищем директорию, в которой уста-
Таблица tbUsers (в которой мы видим созданных пользователей).
новлен WinRadius, и находим там файл WinRadius.mdb.
! Нажимаем «OK».
Настраиваем DSA-3100 на работу с сервером RADIUS
Создаём 5 пользователей (больше, к сожалению, нельзя, демоверсия WinRadius не позволяет), всем назначаем аккаунтинг на базе использованного трафика. Затем пробуем аутентифицироваться: на компьютере, который подключён к Authentification-порту DSA-3100, набираем какой-либо URL, шлюз перехватывает http-запрос и выдаёт нам форму для аутентификации (всё, разумеется, под защитой SSL). Процесс аутентификации и завершение пользовательской сессии отображается в окне WinRadius. Все данные, которыми оперирует WinRadius, хранятся в базе данных (данные – это пользовательские аккаунты и логи). Откроем в MsAcсess файл WinRadius.mdb и посмотрим, как выглядит база данных нашего RADIUS – а выглядит она довольно просто. Видим в ней несколько таблиц. Таблица tbLogs (в ней записались все данные об объеме трафика, который прокачали 5 тестовых пользователей).
24
Итак, вроде бы всё очень хорошо: пользователи аутентифицируются, и трафик считается. Единая база данных позволяет осуществлять роуминг между HOTSPOT, разбросанными по всему городу. Между точками доступа внутри хотспотов также осуществляется роуминг при помощи протокола IAPP (Inter Access Point Protocol). Однако чего-то всётаки не хватает. А не хватает следующего: возможности пользователям просматривать текущее состояние своего счёта, возможности пополнять счёт (чтобы это мог делать сам пользователь или администратор/оператор системы). Кроме того, не помешает наличие возможности удобного администрирования системы, в которой, например, будет несколько NAS-серверов DSA-3100 (сеть хотспотов или интернет-кафе), т.е. количество пользователей будет довольно приличным. Как же всё это реализовать? Ответ напрашивается сам собой: нужно сделать пользовательский и администраторский веб-интерфейс, который будет брать/класть данные в нашу базу данных. Пусть всё это работает на веб-сервере, работающем на том же компьютере, на котором работает RADIUS. Веб-сервер мы поместим в зону, свободную для просмотра ( DSA-3100 позволяет это сделать), чтобы даже пользователи с нулевым и отрицательным балансом могли зайти на страницу статистики/пополнения счёта. Выбираем веб-сервер: компьютер у нас под Win2k Server, значит, скорее всего, будем использовать Apache для Windows или IIS (Internet Information Services). Если выберем Apache, то будем писать веб-страницы со скриптами на PHP (Perl и т. д. и т. п.). Если же выберем IIS, тогда будем использовать технологию ASP (Active Server Pages). Веб-страницы со скриптами в этом случае будем писать на VBS (Visual Basic Script – этот язык очень похож на бейсик, который все мы изучали в школе) или на JavaScrip. Есть, конечно, ещё много различных вариантов, на чём писать и что использовать, я перечислил то, что лежит на поверхности. Остановимся, пожалуй, на IIS с ASP и VBS – вариант наиболее простой для понимания и освоения. Весь перечисленный функционал реализовывать не будем, но коечто всё-таки покажем для примера.
на правах рекламы Создаём сайт на веб-сервере IIS
! Control Panel → Administrative Tools → Internet Services Manager (оснастка, управляющая IIS).
! Правой мышкой по компьютеру → New → Web Site →
запустился мастер → пишем название сайта (любое) → назначаем ему IP-адрес → указываем папку, которая будет домашним каталогом сайта (туда будем складывать веб-странички со скриптами) → ничего не трогаем, жмём «Next» → «Finish». Сайт готов, он появился в левой половине оснастки.
!
Скрипт №1 Для начала сделаем страницу со скриптом, который просто обращается к нашей БД и полностью извлекает оттуда содержимое таблицы tbLogs. Делать можно в чём угодно, в том числе и в блокноте (номера строк писать не надо – это для удобства комментирования). Файл назовём bd.asp; сохраним его в домашний каталог сайта.
! !
bd.asp 1 2 3 4 5 6 7 8
<html> <head> <title>tbLogs</title> </head> <body bgcolor="#FFFFFF" text="#000000"> ------ Òàáëèöà <b>tbLogs</b> ------- <br><br>
!
<% set MyConnection = ↵ Server.CreateObject("ADODB.Connection")
9 10 MyConnection.Open "Driver={Microsoft Access Driver ↵ (*.mdb)};" & _ 11 "DBQ=WinRadius.mdb;" & _ 12 "DefaultDir=C:\(radius)\WinRadius;" & _ 13 "Uid=Admin;Pwd=;" 14 15 set rsLogs=MyConnection.Execute ("SELECT * FROM tbLogs") 16 17 response.write "<table width=90% border=1 ↵ cellspacing=0 align=center><tr><td><b>happen</b></td>" 18 response.write ↵ "<td><b>username</b></td><td><b>duration</b>" 19 response.write ↵ "</td><td><b>input</b></td><td><b>output </b></td><td>" 20 response.write "<b>fee</b></td></tr>" 21 22 do while not rsLogs.EOF 23 response. write "<tr>" 24 response.write "<td>" & rsLogs("happen") & ↵ "</td><td>" & rsLogs ("username") & "</td><td>" & ↵ rsLogs("duration") 25 response.write "</td><td>" & rsLogs ("input") & ↵ "</td><td>" & rsLogs ("output") & "</td><td>" & ↵ rsLogs ("fee") & "</td>" 26 response. write "</tr>" 27 rsLogs.movenext 28 loop 29 30 response.write "</tr></table>" 31 rsLogs.Close 32 rsLogs = null %> 33 </body> 34 </html>
! ! ! ! !
параметры соединения с БД (по порядку): драйвер, имя файла БД, директория с файлом БД (не забудьте вписать туда директорию, в которой лежит WinRadius.mdb), имя, пароль (пароль не задан и это, конечно же, надо тоже исправить). Строка 15: при помощи метода Execute объекта My Connection выполняем SQL-запрос и ответ помещаем в переменную rsLogs (которая является набором записей, содержащим результат запроса к БД). Структура этой переменной определяется запросом, т.е. если на выходе будет таблица, то rsLogs будет иметь структуру данной таблицы. Чтобы вывести данные из этой переменной, надо организовать цикл, выполняющийся до тех пор, пока набор записей не будет прочитан, что мы и делаем в последующих строках (22-28). Строки 17-21: делаем шапочку для таблицы, в которой будут отображены данные, считанные из БД. Строка 22: начало цикла, в котором будем читать и выводить содержимое переменной rsLogs до тех пор, пока её полностью не прочитаем (not rsLogs.EOF). Строки 23-26: выводим набор записей из rsLogs в таблицу на печать (т.е. на экран). Делаем это при помощи метода write объекта Response. Если содержимое вывода является HTML, то помещаем его в кавычки; если содержимое вывода какая-либо переменная, то пишем её без кавычек. HTML и переменные можно чередовать в выводе, объединяя их символом «&». Строка 27: перемещаемся на следующую строку набора записей, содержащихся в rsLogs. Строка 28: идём в начало цикла. Строка 30: закрываем теги <tr> и <table>, которые мы открыли перед циклом вывода данных (22-28). Строки 31-32: закрываем набор записей rsLogs и скрипт символом «%>». Строки 33-34: конец страницы. Результат обращения к данной странице:
Разбор bd.asp:
! Строки 1-6: здесь всё понятно – простой HTML. ! Строка 8: значок «<%» открывает скрипт. При помощи метода CreateObject объекта Server создаётся соединение ADO – MyConnection (которое в свою очередь тоже является обьектом и имеет набор свойств и методов). ! Строки 10-13: при помощи метода OPEN объекта MyConnection открывается соединение с базой данных RADIUS. В строке соединения (строки 11-13) задаются
№1, январь 2005
Набираем в браузере: http://IP веб-сайта/bd.asp. В ответ получаем содержимое таблицы БД, в которую сложились логи с DSA-3100, выступающего в качестве NAS (думаю, что у всех всё заработало).
25
администрирование Скрипт №2
39 40 41 42 43 44 45
Теперь реализуем функционал, позволяющий пользователю смотреть статистику своих соединений, страницу статистики защитим паролем. Вся обработка обращения пользователя осуществляется одной страницей, в которой будет выполняться та или иная часть скрипта в зависимости от того, что пользователь введёт в поля «логин» и «пароль» (этот метод называется «рекурсивная обработка формы»). Файл назовём bd2.asp, его также сохраним в домашнем каталоге сайта. Логика работы страницы следующая: 1. Проверяем, введено ли что-нибудь в поля «логин» и «пароль»: ! если оба поля не заполнены, или не заполнено какое-либо одно поле, то снова выдаём пустую форму (т.е. возвращаемся к пункту 1); ! если оба поля заполнены, то переходим к пункту 2. 2. Обращаемся к БД и проверяем правильность логина и пароля: ! если пароль и логин правильные, то выдаём пользователю статистику его соединений; ! если неправильные, выдаём сообщение «Неправильное или несуществующее имя пользователя или пароль!».
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
<html> <head> <title>tbLogs</title> <META http-equiv=Content-Type content="text/html; ↵ charset=windows-1251"> </head> <body bgcolor="#FFFFFF" text="#000000"> <% Dim sSearchLogin Dim sSearchPassword sSearchLogin = Request.Form("login") sSearchPassword = Request.Form("password") if sSearchLogin = "" or sSearchPassword = "" Then response.write "<div align=center> <table ↵ cellpadding=10><tr><td ↵ bgcolor=#CC6600>&nbsp;</td></tr></table>" response.write "<p><b><font color=#CC6600>Mega ↵ Wi-Fi network billing system ↵ </font></b></p><p>&nbsp;</p> <p><br><br>" response.write "--- Ñåðâåð ñòàòèñòèêè --- " response.write "<form name=form method=post ↵ action=bd2.asp><table align=center border=1><tr> ↵ <td ><b>Ëîãèí:</b></td><td > " response.write "<input type=text name=login> ↵ </td></tr><tr><td ><b>Ïàðîëü:</b></td><td> " response.write "<input type=password ↵ name=password><input type=submit name=Submit ↵ value=âõîä> </td></tr></table></form>" Response.End
! Строки 1-6: здесь всё понятно – простой HTML. ! Строка 7: значок «<%» открывает скрипт. ! Строки 8,9: объявляем переменные, в которые считаем
End If %> <% set Connection = Server.CreateObject("ADODB.Connection")
! Строки 11,12: получаем логин и пароль из POST-запроса. ! Строка 14: начало условия (проверяем введено ли имя
Connection.Open "Driver={Microsoft Access Driver ↵ (*.mdb)};" & _ 30 "DBQ=WinRadius.mdb;" & _ 31 "DefaultDir=C:\(radius)\WinRadius;" & _ 32 "Uid=Admin;Pwd=;" 33 34 strSQL="SELECT password FROM tbUsers ↵ WHERE username = " & "'"& sSearchLogin &"'" 35 36 set rsUsers=Connection.Execute (strSQL) 37 pas="" 38 do while not rsUsers.EOF
26
If pas = sSearchPassword then
strSQL1="SELECT * FROM tbLogs ↵ WHERE username = " & "'"& sSearchLogin &"'" 46 set rsLogs1=Connection.Execute (strSQL1) 47 48 response.write "<P align=center>Ëè÷íàÿ ñòàòèñòèêà ↵ ïîëüçîâàòåëÿ <b>" & sSearchLogin & "</b></p><br><br>" 49 response.write "<table width=90% border=1 ↵ cellspacing=0x align=center><tr><td><b>íà÷àëî ↵ ñåññèè</b></td>" ↵ 50 response.write "<td><b>username</b></↵ td><td><b>ïðîäîëæèòåëüíîñòü [ìèí]</b>" 51 response.write "</td><td><b>input ↵ [Mb]</b></td><td><b>output[Mb] </b></td><td>" 52 response.write "<b>ñòîèìîñòü [$]</b></td></tr>" 53 do while not rsLogs1.EOF 54 input=input+rsLogs1("input") 55 output=output+rsLogs1("output") 56 duration=duration+rsLogs1("duration") 57 fee=fee+rsLogs1("fee") 58 59 response. write "<tr>" 60 response.write "<td>" & rsLogs1("happen") & "</td><td> ↵ " & rsLogs1("username") & "</td><td>" & ↵ round((rsLogs1("duration")/60),2) 61 response.write "</td><td>" & Round(((rsLogs1 ↵ ("input"))/1024/1024) ,3) & "</td><td>" & ↵ Round(((rsLogs1 ("output"))/1024/1024) ,3) 62 response.write "</td><td>" & ((rsLogs1("fee")) /100) ↵ & "</td>" 63 rsLogs1.movenext 64 response. write "</tr>" 65 loop 66 67 response.write "</tr></table>" 68 response.write "<br><br><br><P ↵ align=center>__________________________________<br>" 69 response.write "ñóììàðíûé èñõîäÿùèé òðàôèê: <b>" & ↵ round((output/1024/1024),3) & "</b> Mb<br><br>" 70 response.write "ñóììàðíûé âõîäÿùèé òðàôèê: <b>" & ↵ round((input/1024/1024),3) & "</b> Mb<br><br>" 71 response.write "ñóììàðíàÿ ïðîäîëæèòåëüíîñòü ñåññèé: ↵ <b>" & round((duration/60/60),2) & "</b> ÷àñîâ <br><br>" 72 response.write "ðàñõîä çà îò÷¸òíûé ïåðèîä: <b>" & ↵ (fee/100) & "</b> $ ↵ <br>__________________________________________<br></p>" 73 rsLogs1.Close 74 rsLogs1 = null 75 response.end 76 77 End If 78 79 response.write "Íåïðàâèëüíîå èëè íåñóùåñòâóþùåå èìÿ ↵ ïîëüçîâàòåëÿ èëè ïàðîëü!" 80 %> 81 82 </body> 83 </html>
bd2.asp 1 2 3 4
pas=rsUsers("password") rsUsers.movenext loop
Разбор bd2.asp :
из формы логин и пароль.
! ! ! ! !
пользователя и пароль – сравниваем то, что получили из запроса с пустотой). Строки 16-22: выводим чистую форму, если пользователь не заполнил оба или одно из полей «логин» и «пароль». Строка 24: конец условия. Строка 25: конец скрипта. Строка 26: начало нового скрипта, который будет выполняться в том случае, если имя и пароль введены. Строка 27-32: подключаемся к БД.
на правах рекламы ! Строка 34: формируем SQL запрос к БД, который выби! ! !
!
!
! ! !
рает пароль для пользователя с именем, которое введено в форму. Строка 36: выполняем запрос. Строка 37: объявляем переменную «pas» и приравниваем её к пустой строке. Строки 38-41: читаем набор записей, в котором содержится ответ на SQL-запрос, и присваиваем его значение переменной «pas». Если бы в базе не нашлось пароля для введённого имени, тогда бы переменная «pas» осталась бы пустой. Строка 43: если выбранный пароль совпадает с введённым, то выполняем с 45 по 76 строку; если не совпадает, тогда выполняем строку 80 – выдаём «Неправильное или несуществующее имя пользователя или пароль!». Строки 45-76: делаем запрос к БД, в ответ получаем выборку для нужного пользователя. Выводим статистику на экран в удобной форме. Response.End (76 строка) означает конец вывода. Строка 77: конец условия. Строка 79: если условие не выполнилось, т.е. пользователь ввёл неправильный пароль или имя, – выдаём соответствующее сообщение. Строки 83-84: конец страницы.
Результат обращения к bd2.asp (результат выполнения скрипта) Заходим на страницу, получаем форму для ввода логина и пароля (неплохо было бы и здесь использовать SSL, чтобы злоумышленники не перехватили открытый POST-запрос c логином и паролем, но о том, как прикрутить SSL к IIS как-нибудь в другой раз – это довольно-таки легко сделать при помощи пакета OpenSSL).
№1, январь 2005
Вводим правильные логин и пароль, получаем результат (если логин или пароль неправильные, то ничего не получаем). Поздравляю! Мы написали хотспотный биллинг.
Выводы На первый взгляд всё довольно сложно и запутанно. Но если разобраться, ничего сложного нет: NAS-серверы, в роли которых выступают DSA-3100, проводят аутентификацию пользователей и пишут CDR-подобную статистику в единую базу данных RADIUS. Для реализации различных дополнительных (практически любых) функций биллинга разрабатываем веб-интерфейс, для чего используем, например, ASP или PHP. Тарификация пользователей может осуществляться на основе использованного времени или по трафику. В случае с одиночно стоящим хотспотом – сервисный шлюз DSA-3100 и тикет-принтер DSA-3100P – являются биллингом во плоти, никаких гаек подкручивать не надо, с построением хотспота справится любой, но тарификация будет вестись только по времени. Возможно, многих озаботит немалое количество дорогого программного обеспечения, которое необходимо задействовать совместно с шлюзом в случае построения сети хотспотов, однако я никого не призываю покупать именно это ПО. Я говорю следующее: есть простые HOTSPOT и для этого подойдёт DSA-3100 – любой – опытный и не очень пользователь может его себе поставить и всё заработает с полоборота. Но бывают сложные решения, и этот шлюз может, несмотря на всю его простоту, быть использован и для сложного решения. Я показал на базе продуктов от Microsoft и RADIUS-сервере под Windows, какую роль будет выполнять шлюз в этом случае. Microsoft – это просто, визуально, понятно любому. Либо можно использовать связку: Linux + (WEB)Apache/php + (БД)Oracle + (RADIUS)Radiator + NAS(DSA-5100). Видимо, наиболее применимы эти устройства будут для организации точек HOTSPOT в кафе, ресторанах, гостиницах и прочих заведениях. Но возможно их использование и для серьёзных операторских решений, потому как любой уважающий себя биллинг поддерживает протокол RADIUS. При помощи данных устройств можно легко интегрировать HOTSPOT в сеть сотового оператора. Такое решение, например, представил «Енисейтелеком» (это ведущий оператор сотовой связи в Красноярском крае) на выставке «Связь – ИНФОКОМ 2004»: пользователи отправляли sms на сервисный номер оператора и получали в ответ sms-сообщение с именем и паролем для доступа в Интернет. Шлюз взаимодействовал с биллингом оператора (он поддерживал протокол RADIUS), деньги за пользование услугой снимались с сотового счёта абонента. Очень оригинальная и комфортная с точки зрения пользователя HOTSPOT схема доступа к услуге. Вместе с тем шлюз DSA-3100 сможет сэкономить немало времени на настройку авторизации и тарификации администратору обычной проводной (в том числе домашней) сети, предоставив в его распоряжение надежную систему авторизации по IP + MAC в совокупности с авторизацией по логину и паролю.
27
безопасность
ОРГАНИЗАЦИЯ ОБЩЕГО ДОСТУПА В ИНТЕРНЕТ И ЗАЩИТЫ ОТ ВТОРЖЕНИЙ НА ОСНОВЕ Kerio WinRoute Firewall 6
РОМАН МАРКОВ 28
безопасность Данная статья – попытка помочь начинающим системным администраторам получить первоначальные навыки предоставления общего доступа в Интернет и защиты локальной сети от внешних вторжений. Это не подробное описание всех возможностей данного продукта, а методика настройки – от момента установки до начала работы пользователей. В ней рассматривается организация шлюза в Интернет на основе выделенного компьютера с двумя сетевыми картами.
Выбор оборудования и первоначальная настройка системы и локальной сети Описываемая система будет крайне непритязательна к аппаратным ресурсам. Фактически требования совпадают с требованиями устанавливаемой операционной системы. То есть для среднего сервера, предназначенного для предоставления общего доступа в Интернет на скорости до 128 Кбит/сек для 5-7 пользователей, достаточно будет компьютера Celeron 300-400 МГц, 128 Мб RAM, 5-10 Гб HDD. Исходя из опыта автора данной статьи, можно также сказать, что роль такого сервера (Маршрутизатор, Проксисервер, Firewall, Почтовый сервер, FTP-сервер) для 10-15 пользователей прекрасно может выполнять компьютер следующей конфигурации: Intel Celeron 733, 256 Мб RAM, HDD 10 Гб IDE с установленной операционной системой Windows 2000 Server. Принципиальное отличие данной системы от распространенных решений, основанных на анализе сторонними программами журналов доступа к прокси-серверу – это возможность наиболее простым способом организовать офисную биллинговую систему для любого трафика пользователей, проходящего через NAT. Также важным нововведением является функция мгновенного отключения пользователю доступа в Интернет при превышении персонального лимита. При анализе же журналов доступа при помощи сторонних программ изменение статистики происходит дискретно, через заданный промежуток времени. Помимо этого, в распространенных простых системах анализируется только трафик приложений через прокси-сервер, а не весь трафик пользователя. Если количество пользователей колеблется от 20 до 50, то для абсолютной уверенности в надежности и скорости работы подобного сервера рекомендуется использовать следующую конфигурацию оборудования: Intel Pentium II-III (Celeron) 1000-1500 МГц, 512 Мб RAM, HDD 18 Гб SCSI. Но это уже вопрос финансов. SCSI-диски рекомендуется использовать для надежности и увеличения скорости доступа к кэшу прокси-сервера. Крайне рекомендуется использовать SCSI-диски, если вы будете применять систему статистики по пользователям – процедура записи и анализа журнала запросов очень сильно нагружает именно дисковую систему.
Настройка операционной системы На внутреннем сетевом интерфейсе не должно быть прописано шлюза по умолчанию! В качестве DNS-сервера на нем прописываем либо DNS-сервер провайдера (если нет домена Windows 2000), либо внутренний DNS-сервер локальной сети, в случае если Active Directory поднят. Реко-
№1, январь 2005
мендую в свойствах сетевого окружения сразу переименовать подключения, например «LAN» и «Internet», чтобы в будущем не путаться. Во втором случае надо будет настроить внутренний сервер DNS. В консоли управления DNSсервером правой клавишей мыши кликаем по нужному серверу и выбираем «Свойства». Закладка «Пересылка» (Forwarding). Ставим галочку «Разрешить пересылку» и задаем внутренний адрес нашего сервера общего доступа. Если внутренний DNS-сервер совпадает с нашим сервером общего доступа, то прописываем здесь DNS-сервер провайдера. Если галочка «Пересылка» недоступна, то необходимо удалить зону «.» (точка) из списка зон вашего DNS-сервера, закрыть консоль DNS и заново открыть. Изменения могут вступить в силу в течение 15 минут, так что не волнуйтесь, если галочка «Пересылка» не стала доступна сразу после удаления зоны «.». Закройте оснастку DNS и подождите некоторое время. Затем заходим на закладку «Корневые ссылки» (Root Hints). Удаляем там все, что видим, так как разрешением DNS занимается провайдер, а не ваш шлюз напрямую. Иначе при некорректной настройке вы рискуете получить довольно большой паразитный трафик от DNS-запросов к корневым интернет-серверам. Подробная инструкция по настройке DNS-сервера домена Windows 2000/2003 приведена в октябрьском номере журнала – в статье «Установка и настройка W2K Server». Затем настраиваем свойства сетевого подключения к интернет-провайдеру. Подразумевается, что эти действия производит либо ваш провайдер, либо вы по инструкции провайдера. Внимание: рекомендуется подключать кабель внешней сетевой карты (к интернет-провайдеру) только после установки Kerio WinRoute Firewall. В противном случае вы рискуете тут же подвергнуться вирусной атаке. Из опыта автора статьи: иногда достаточно нескольких минут работы без межсетевого экрана, чтобы поймать червя семейства Blaster или Sasser. Обязательно снимите галочки с привязок «Клиент для сетей Microsoft» и «Служба доступа к файлам и принтерам» в свойствах внешнего интерфейса. После этого приступаем к установке Kerio WinRoute Firewall 6.
Установка Дистрибутив скачиваем с официального сайта http:// www.kerio.com/kwf_download.html. Это trial-версия, работающая в течение 30 дней – срока, достаточного для тестирования продукта. Потом необходимо приобрести лицензию. Trial-версия полностью функциональна. Запускаем программу установки, принимаем лицензионное соглашение и указываем путь расположения файлов. При необходимости получения постоянного контроля за трафиком пользователей и анализа журналов доступа рекомендуется использовать SCSI-диск, так как данный тип дисков является наиболее отказоустойчивым при большом количестве дисковых операций в единицу времени. Затем выбираем тип установки: «Custom». После этого нам предложат выбрать необходимые компоненты. Если мы не пла-
29
безопасность нируем использовать WinRoute для организации VPN-канала между сетями, то снимаем галку «VPN Support». Файлы помощи на чешском языке нам тоже вряд ли понадобятся. Поэтому снимаем галку «Czech» внутри опции «Help Files». Переходим к следующему экрану.
Создаем первую учетную запись администратора и пароль. Внимание! Поменяйте имя предложенной записи «Admin» на другое. Задайте и подтвердите для нее сложный пароль (в противном случае вы рискуете подвергнуться атаке злоумышленников). Переходим к следующему экрану. Программа предупреждает нас о том, что после установки по умолчанию будет блокирован любой сетевой трафик, поэтому если вы в момент установки конфигурируете сервер общего доступа удаленно – укажите внутренний IP-адрес, с которого необходимо разрешить доступ к удаленному конфигурированию. Для дальнейшего конфигурирования WinRoute через Интернет необходимо будет добавить соответствующее разрешение в Traffic Policy. Например, IPадрес рабочей станции, с которой производится удаленное конфигурирование.
Если в процессе установки мы получим сообщение о том, что данное программное обеспечение не тестировалось или не подписано – не обращаем внимания и выбираем продолжение установки. После установки будет предложено перезагрузить компьютер. Помните, что если вы конфигурируете компьютер, вхо-
30
дящий в домен при помощи терминального доступа (Remote Desktop), то после перезагрузки войти в него при помощи доменной учетной записи вам, скорее всего, не удастся. Придется использовать либо учетную запись локального администратора, либо не использовать терминальный доступ, а войти на сервер локально. Честно говоря, не совсем понятно, почему это происходит. Возможно, что будет исправлено в последней версии (автор использовал 6.0.4). При экспериментах создалось впечатление, что трафик авторизации блокировался в момент первого входа. Итак, регистрируемся с учетной записью администратора любым возможным способом. Если предлагают запустить консоль администрирования WinRoute – отказываемся. В меню «Пуск → Программы → Kerio → WinRoute Firewall» запускаем Engine Monitor. В системном трее появится значок WinRoute. Щелкаем по нему правой клавишей мыши и выбираем «Startup Preferences». В открывшемся окне устанавливаем обе галочки. Первая – задает автоматический запуск сервиса WinRoute, а вторая – автоматический запуск его монитора в системном трее.
Дважды щелкаем на значке WinRoute в трее и вводим адрес нашего сервера WinRoute, а также данные созданной нами учетной записи администратора. Если WinRoute установлен на этом же компьютере – оставляем в поле адреса «Localhost».
Запустится мастер (Network Rules Wizard), который поможет произвести первоначальную настройку. Тут есть два варианта – либо воспользоваться мастером, либо отказаться от него и настроить все вручную. Если вы досконально понимаете, что именно необходимо настраивать, можно выбрать второй метод. Мы опишем настройку при помощи мастера, так как она без особых хлопот позволяет организовать настройку защиты и общего доступа «за 7 кликов мышью».
безопасность Настройка при помощи мастера
Настройка базы пользователей
Соглашаемся с предложением мастера продолжить настройку. На втором шаге выбираем тип нашего соединения с Интернетом. В нашем случае это «Ethernet, DSL, cable modem or other». На следующем шаге выбираем тот сетевой адаптер, который подключен к сети Интернет. Если в списке не появился нужный нам адаптер – подключите сетевой кабель к нему и заново запустите мастера. Шаг 4 позволит нам решить – к каким именно внешним сервисам разрешено будет обращаться клиентам локальной сети. Рекомендуемый минимум: HTTP и HTTPs. Если помимо просмотра веб-страниц клиенты локальной сети должны получать почту с внешних почтовых ящиков по протоколам POP3, IMAP, а также отправлять по SMTP – устанавливаем необходимые галочки. То же самое с доступом к внешним FTP-серверам. Прямое разрешение имен DNS через Интернет для клиентов локальной сети не является необходимым – наш шлюз будет перенаправлять такие запросы и возвращать ответы. Затем отвечаем на вопрос, будем ли мы использовать VPN-соединение средствами WinRoute. На шаге 6 можно указать внутренние сервера, к которым необходимо дать доступ из внешней сети, т.е. Интернета. Например, внутренние Web, FTP или почтовые сервера. Если мы вообще не хотим предоставлять доступ к нашей сети извне – не добавляем никаких правил. ! Добавим доступ из Интернета к удаленному управлению рабочим столом (Terminal Services) нашего шлюза. Нажимаем Add… В поле «Service is running on» – указываем «Firewall». В поле «Service» выбираем «RDP». ! Теперь добавим доступ к внутреннему веб-серверу, расположенному на другом компьютере с IP-адресом 192.168.0.5. Снова нажимаем Add… В поле «Service is running on» – указываем «IP address – 192.168.0.5». В поле «Service» выбираем «HTTP».
Теперь наша задача – создать или импортировать из базы Active Directory учетные записи пользователей. Если доменная структура не используется, то всех пользователей придется завести вручную. Заведение пользователей вручную аналогично описанной ниже процедуре создания шаблона автоматически импортируемых пользователей (Define User Template). Открываем консоль Users and Groups. Сначала создадим две основные группы: Admins и Users. В группу Admins мы включим учетные записи администраторов нашего шлюза, а в группу Users – обычных пользователей, которые должны будут получать доступ в Интернет. Добавляем в группу Admins единственного на данный момент пользователя нашего брандмауэра – учетную запись, с которой мы регистрируемся для конфигурирования WinRoute, выбираем опцию «Full Access to administration» и, при необходимости, все нижеследующие галочки. Опишем их назначение: ! Users can override WWW content rules – разрешает пользователям доступ к запрещенным в Content Rules ресурсам. Установка этой опции делает доступными все просматриваемые ресурсы, независимо от явных запретов в правилах. ! Users can unlock URL rules – пользователи могут разблокировать запрещенные ссылки. При посещении запрещенной ссылки пользователю выдается окно с указанием, что посещение данного ресурса запрещено правилами, однако предлагается отменить этот запрет нажатием на ссылку «Unlock». ! Users can dial RAS connection – пользователи имеют право инициировать соединение через RAS (модемное подключение, например). ! Users can connect using VPN – пользователи имеют право инициировать VPN-соединение. ! Users are allowed to use P2P networks – пользователям разрешено пользоваться P2P-сетями (Kazaa, Edonkey и пр.).
По аналогии конфигурируем доступ из Интернета к другим внутренним службам. Шаг 7 предоставляет возможность организовать общий доступ для клиентов локальной сети наружу при помощи технологии NAT. Соглашаемся с предложением мастера (галочка «Enable NAT»). Если мы согласны с указанными настройками, то на 8-м шаге нажимаем кнопку «Далее». Все, первоначальные настройки сделаны!
№1, январь 2005
Затем открываем консоль Users and Groups, в ней – Users. Переходим на закладку – Authentication Options. Устанавливаем опцию «Always require users to be authenticated when accessing web pages». Опция «Automatically logout users when they are inactive» задает период в минутах, после которого пользователь, не проявлявший активности, будет отключен от брандмауэра. В этом случае при следующем обращении к веб-ресурсам окно аутентификации появится вновь. Данная опция позволяет предотвратить использование «чужого» входа в систему для просмотра веб-страниц. То есть, даже если пользователь оставил свой компьютер незаблокированным, через указанное время происходит отключение его сеанса доступа в Интернет. Если мы импортируем учетные записи пользователей из домена Active Directory, то переходим к закладке Active Directory/NT Domain и устанавливаем опцию Enable Active Directory authentication. Если же используется домен NT, то устанавливаем галочку Enable NT Domain authentication в нижней части закладки.
31
безопасность
Задаем имя домена. Далее у нас есть два пути: Нажимаем Import Users Accounts Now и отмечаем галками тех пользователей, которых хотим импортировать. Очень большой минус этого метода заключается в том, что тогда каждому пользователю придется вручную задавать принадлежность к группе, права доступа и персональный лимит. При количестве пользователей более 20 это очень утомительно. Более рациональный способ. Разрешаем автоматический импорт учетных записей из Active Directory – Automatically Import User Accounts from Active Directory. Указываем имя сервера, с которого будет производиться чтение учетных записей, а также специальную учетную запись, единственное предназначение которой – получить доступ Read-Only к базе AD. Пользователи будут добавляться в базу WinRoute по мере их обращения к ресурсам Интернета. То есть WinRoute проверяет, существует ли в домене указанная учетная запись и если указанные пользователем при первом входе данные совпадают с данными домена – пользователь автоматически прописывается в базу WinRoute и получает стандартные настройки. Их создание описано ниже. Нажимаем кнопку Define User Template. Указываем группу пользователей, к которой автоматически будут причисляться новые пользователи (в нашем случае – Users). В закладке Rights оставляем все по умолчанию – No access to administration и никаких Additional Rights (либо указываем те, которые необходимы. Описание дополнительных прав приведено выше). В закладке Quota задаем лимит трафика по умолчанию. Есть возможность задать два типа ограничений – на суточный трафик, и на суммарный месячный. Причем оба параметра могут существовать одновременно. То есть даже если пользователю задан месячный лимит на 100 Мб, можно указать, что за день он не имеет права использовать более 4 Мб. Тогда вы гарантированно избавляетесь от проблем, связанных с использованием всего месячного лимита за один день и последующего обивания вашего порога с криками: «Интернет нужен мне по работе! Немедленно верните Интернет!». Здесь же можно указать, на какой именно трафик устанавливается лимит – входящий, исходящий или суммарный. Чаще всего оплачивается входящий трафик, хотя бывают и другие тарифы. Уточ-
32
ните у своего провайдера. Очень полезна опция «Quota Exceed Action». В этой части задается действие, которое необходимо произвести при превышении пользователем своей квоты. Generate Alert Message Only – пользователь получит сообщение о превышении персонального лимита, но не лишится доступа в Интернет. Do not allow the user to open new connection – запрещает пользователю создавать новые соединения, однако те, которые в данный момент активны, продолжат свое существование. Например, если пользователь закачивает большой файл и его лимит оказывается превышен на середине процесса закачки – WinRoute все равно позволит скачать этот файл, а затем запретит доступ. Kill all users connections immediately – наиболее полезная и долгожданная для многих администраторов опция. При превышении персонального лимита все соединения пользователя отключаются. В отличие от предыдущего пункта, даже если пользователь закачивает большой файл, при достижении лимита все его соединения отключаются. Следует помнить, что небольшая погрешность все-таки существует, так как счетчики не обновляются мгновенно. То есть в зависимости от скорости соединения пользователь всетаки немного превысит допустимый трафик (при высокой скорости величина превышения может колебаться до 1 Мб). В закладке Content Rules можно принудительно запрещать или разрешать использование различных скриптов, таких как ActiveX, Java-Script и пр.
Настройка клиентов Настройка клиентов крайне проста. В свойствах сетевого подключения по локальной сети указываем шлюз по умолчанию (Default Gateway) – внутренний адрес созданного нами сервера общего доступа. В качестве DNS-сервера указываем либо внутренний DNS-сервер (при наличии домена Active Directory), либо тот же внутренний адрес нашего шлюза. Все! Принципиально новое неоспоримое преимущество нового продукта от Kerio в том, что можно забыть про указание прокси-сервера в свойствах приложений. При поступлении запроса от клиента WinRoute 6 сам определяет его тип (браузер, FTP и т. д.) и обрабатывает соответствующим образом. Больше не нужно заботиться о том, чтобы клиенты использовали прокси-сервер для просмотра веб-страниц, для контроля расхода интернет-трафика. Kerio WinRoute Firewall 6 принудительно подсчитает трафик. Проверяем, все ли корректно настроено. На клиенте откроем интернет-браузер и попробуем посетить любую страничку. При первом подключении к ресурсам внешней сети будет выведен запрос о перенаправлении на защищенное соединение и при подтверждении выведено окно авторизации. В нем вы должны указать корректное имя пользователя и пароль. После этого авторизация будет проходить для новых соединений автоматически. Если после авторизации запрошенная страница не открылась – попробуйте ввести адрес еще раз. Запрос авторизации появляется только один раз. Дальше (до истечения выставленного тайм-аута авторизации) авторизация осуществляется автоматически.
безопасность На этом минимальная настройка для полноценной работы закончена. Далее будут описаны продвинутые концепции: использование фильтра Cobion, ручная настройка Traffic Policy и пр. Акцентирую ваше внимание, что настройку Traffic Policy вручную рекомендуется проводить только если вы в совершенстве знаете механизмы обмена в IPсетях. В противном случае рискуете подвергнуть локальную сеть атакам злоумышленников, а также предоставить пользователям полный неконтролируемый доступ к внешним ресурсам.
Настройка фильтров HTTP, FTP и Cobion Переходим в консоль Content Filtering. Выбираем HTTP. Рассмотрим доступные закладки в порядке их использования: URL Rules: Правила фильтрации контента по вхождению значений в URL ресурса. По умолчанию (и для примера) здесь уже созданы несколько правил. Разрешающие – для Windows Update и Kerio Update. А также запрещающие: для фильтрации рекламы и трафика по категориям в фильтре Cobion. Kerio умеет подменять баннеры своими собственными изображениями, чтобы форматирование страницы не рушилось. Можно либо выводить «пустое место», либо перенаправлять запрос на другой ресурс. Комплексное использование и тонкая настройка этих фильтров успешно решают проблему запрета доступа к огромному количеству нежелательных ресурсов. Использование фильтров Cobion позволяет ограничивать доступ к ресурсам не на основе маски URL, а по простому смысловому вхождению. Рассмотрим настройку фильтров на конкретном примере, поясняя неоднозначные действия. Итак: Закладка URL Rules: Оставляем правила Windows Update и Kerio Update как есть. Устанавливаем галку на правиле «Remove Advertisement and banners», открываем правило двойным щелчком мыши. Можно переименовать правило так, как удобно, а также настроить особенности его применения.
If user accessing the URL is – здесь можно выбрать распространение правила на всех пользователей, либо указать принадлежность пользователя к группе. And URL matches criteria – задает категорию ресурсов, на которые распространяется правило. Можно указать мас-
№1, январь 2005
ку, с которой начинается ссылка, выбрать группу адресов, указать на поиск в рейтинге фильтра Cobion, а также указать, что необходимо производить данное действие над ресурсами, которые не имеют DNS-имени, а адресуются простым указанием IP-адреса. Наиболее удобные и рациональные способы – это задание групп адресов, а также использование фильтра Cobion. Группе может соответствовать много разных критериев, которые рассматриваются по принципу «OR» (логическое ИЛИ), а смысловые фильтры Cobion вообще отличаются интеллектуальным механизмом анализа запрашиваемого контента. В разделе Action указывается действие, которое предпринимается при совпадении условий. Закладка Advanced: здесь можно задать дополнительные критерии правила: Valid at time interval – задает интервал времени, в течение которого действует правило. Valid for IP address group – задает группу IP-адресов, на которую будет распространяться это правило. Используя эти параметры, можно гибко настраивать правила фильтрации. Например, задав группу IP-адресов и требуемый интервал действия правила, можно запретить посещать указанные категории ресурсов в рабочее время для группы компьютеров. Например, создавая правило с «URL begin with *» и указывая рабочий временной интервал, мы запретим указанной группе пользоваться доступом в Интернет в рабочее время. Или наоборот – во внерабочее. Все зависит от корпоративной политики предприятия. В Denial Options задается выводимое сообщение, которое появляется при совпадении условий запроса и правила. Можно перенаправлять такие запросы на заданный URL. В закладке Content Rules задаются правила фильтрации, описанные выше, в разделе создания пользовательских шаблонов (Define User Template). Настроим правило с использованием Cobion-фильтра. Оно уже прописано по умолчанию в HTTP-Policy – «Deny sites rated in Cobion categories». По умолчанию фильтры в Cobion отключены. Подключим необходимые вручную. Открываем правило и проверяем, что данный трафик запрещен (Deny access to Web site), а в URL matches criteria установлен переключатель: «Is rated by Cobion Content Rating system». Затем нажимаем справа кнопку «Select Rating» и галочками отмечаем категории, которые необходимо запретить. Каждая категория обладает определенным «весом», который суммируется и, исходя из него, принимается решение о разрешении/запрете объектов. В правом нижнем углу можно настроить «суммарный вес» объектов, при которых запрос к сайту будет отклонен. После этого любая попытка посетить сайт, запрещенный с точки зрения Cobion Rating, окончится выдачей запрещающей страницы с мотивацией этого запрета. То есть пользователь не просто получает отказ сервера, а видит сообщение о том, что данный ресурс входит в запрещенную категорию, с указанием ее названия. Закладка Content Rules задает правила фильтрации HTML-объектов для всего трафика. На закладке Cache есть возможность задать кэширование уже скачанных объектов для ускорения доступа к ним и экономии трафика. Однако экономия трафика не всегда
33
безопасность оправдывает включение кэширования, особенно если задан большой «срок жизни» объектов (TTL). Например, нет смысла кэшировать содержимое сообщений форумов или новостных агентств. Кэширование можно настроить либо на обработку всех запросов без исключения (режим Transparent proxy), либо только тех, что исходят от программ с явными установками параметров прокси-сервера. Параметр HTTP protocol TTL – срок хранения объектов в кэше до их обновления с оригинальных сайтов. При помощи кнопки URL Specific Settings можно задавать исключения для ресурсов по маске. Например, если HTTP protocol TTL установлен в «1», а в URL Specific Settings добавить URL: *forum* и выставить TTL=0, то ресурсы, содержащие в любом месте URL вхождение «forum», кэшироваться не будут. В Cache Options задаются параметры кэширования данных. Опишем их назначение: Continue Aborted Download – продолжает закачку объектов, даже если пользователь ее отменил. Не рекомендуется устанавливать эту опцию, так как потребляемый трафик увеличится непомерно. Keep aborted file in cache – сохраняет в кэше частично закачанные файлы. Рекомендуется установить. Так как при повторном обращении частичный файл будет взят из кэша. Cache responses «302 Redirect» – сохраняет в кэше перенаправления запросов. Use server supplied Time-to-Live – использует параметр TTL, передаваемый целевым сервером. Можно активировать эту опцию, однако это решение спорно, так как некорректно настроенный администратором ресурса параметр TTL может задать объекту слишком большой срок жизни в кэше. Соответственно, пользователи при обращении к ресурсу получат устаревшую информацию. Ignore server Cache-Control directive – игнорирует параметр TTL, передаваемый запрашиваемым сервером. Always validate files in cache – проверяет обновление файла на исходном сервере при каждом запросе, независимо от TTL. Наверное, самый оптимальный параметр настройки, так как минимизирует риск выдачи клиенту устаревшей информации из кэша. На закладке Proxy Server включается непрозрачный прокси-сервер, который и указывается явно в интернет-приложениях. В принципе, если без него все работает – указывать приложениям работу через него не требуется. Это принципиальное отличие от предыдущего продукта (Kerio WinRoute Pro 4) оказалось очень приятным нововведением для администраторов. В URL Groups задаются группы адресов, которые потом можно использовать при создании правил фильтрации. Forbidden Words – набор правил для смыслового-фильтра, который также используется для фильтрации контента (описано выше). Он анализирует информацию подобно поисковой системе. То есть рассматривается не только сама ссылка, но и ее содержание. В этом и есть главное отличие смыслового фильтра от обычных URL-Access-Rules. Справа внизу задается лимит «суммарного веса» наличия на запрашиваемой странице запрещенных слов. Изменяя это значение, а также значения каждого слова, можно добиться оптимальной работы фильтра. Для удобства слова можно объединять в группы. Каждому запрещенному слову необ-
34
ходимо присвоить определенный «вес», который и будет влиять на суммарную политику доступа. Эта фильтрация глобально применяется ко всему httpтрафику и осуществляется после обработки правил URL (только в случае, если доступ к запрошенной странице разрешен). Помимо этого WinRoute 6 имеет встроенный «Cobion Orange Filter». Включить его можно через cледующую консоль «Configuration → Advanced Options → Cobion Settings». Система оценки содержания Cobion – часть системы Cobion, интегрированная в WinRoute. Она позволяет WinRoute оценивать содержание веб-страниц по категориям. Фильтр Cobion использует динамическую международную базу данных, которая включает URL и классификацию интернет-ресурсов. Каждый раз, когда пользователь пытается получить доступ к веб-странице, WinRoute посылает запрос оценки этой страницы. Согласно классификации страницы пользователю будет разрешен или запрещен доступ к странице. Для ускорения работы данные, которые были уже оценены, кэшируются и используются в течение заданного сервером периода. На практике совокупность трех фильтров (URL, Forbidden Words и Cobion) зарекомендовала себя с лучшей стороны. Процент корректного определения запрещенных ресурсов очень велик. Однако, как и любая подобная система, она нуждается в тонкой настройке в процессе эксплуатации. Для этого существуют многочисленные настройки, описанные выше, а также Cobion White List – список ресурсов, которые не требуется оценивать при помощи запросов к базе Cobion. Политика FTP-доступа настраивается аналогично и интуитивно понятна. Отдельного внимания заслуживает раздел Antivirus. В дистрибутив встроен антивирусный продукт McAffee для сканирования всего трафика, проходящего через WinRoute 6. Здесь задается периодичность проверки обновлений (рекомендую выставить 1 час). Помимо проходящего HTTP- и FTP-трафика есть возможность сканировать SMTP- и POP3трафик, отрезая зараженные вложения и (при необходимости) добавляя в тему письма модифицируемое сообщение. Кроме встроенного McAffee, имеется возможность подключать внешние антивирусы (из списка). В настройках антивируса имеется возможность оповещать пользователя по e-mail о том, что он пытался скачать инфицированный объект, перенаправлять зараженные письма администратору, сохранять инфицированные объекты в карантине, а также добавлять в тему письма сигнальные строки. Однако оповещение по e-mail (в отличие от popup-сообщений) не является удобным и актуальным, поэтому проще просто блокировать объект. К сожалению, возможность посылать пользователю мгновенные всплывающие сообщения об обнаружении вируса в его трафике отсутствует. Kerio WinRoute Firewall – очень мощное и многофункциональное средство для защиты и организации общего доступа в Интернет. Описанные возможности составляют лишь половину его функциональности. Система имеет прекрасную встроенную систему помощи (на английском языке), которая поможет получить ответы на многие вопросы, связанные с конфигурированием продукта.
безопасность
ЗАЩИТА ФАЙЛОВОЙ СИСТЕМЫ ПРИ ПОМОЩИ НЕСТАНДАРТНОГО ИСПОЛЬЗОВАНИЯ СНАПШОТОВ В ПРОГРАММЕ ShadowUser ДЕНИС БАТРАНКОВ Что такое снапшот Те, кто знаком с системами архивирования в базах данных, знают, что такое снапшот. Snapshot с английского переводится как снимок. Здесь используется термин из фотографии, поскольку действие этой технологии аналогично снимку фотоаппарата. По сути снапшот – это зафиксированная мгновенно в определенный момент времени копия файловой системы, какого бы большого размера она ни была. Создав такой снапшот, можно заняться архивированием этой огромной «фотографии» на различные внешние носители: магнитную ленту, CD- или DVD-диски. Вся прелесть в том, что, во-первых, все создается мгновенно, во-вторых, сама файловая система продолжает изменяться, а вот ее снапшот (снимок) – нет и, в-третьих, тут нет заблокированных файлов. И действительно, идея неплоха: уже не нужно полностью останавливать базу данных, чтобы выполнить ее архивацию. Перед созданием образа базы данных со снапшота нужно лишь притормозить все файловые операции и скинуть буферы из памяти на диск так, чтобы не было операций, «сфотографированных» посередине выполнения. Для этого XP предоставляет сервис VSS, основанный на COM. Производители могут использовать различные термины для обозначения снапшотов: срез, теневая копия, виртуальный образ, но общая идея их работы от этого не меняется. Мне нравится понятие снимок. В операционной системе Windows (версии NT, 2000, XP, 2003) эта технология реализована специальными драйверами снапшотов от различных производителей. Microsoft начал поддерживать эту технологию в Windows XP и 2003 в виде сервиса Volume Shadow Copy Service (VSS).
настоящая файловая система работает в обычном режиме. Для хранения этих данных требуется свободное место. Где хранятся старые данные, нужно узнавать у каждого производителя драйвера – это важное отличие в реализации технологии. Местом для хранения старых данных может служить другой свободный диск, оперативная память или даже неиспользуемое место на этом же диске. В случае если свободное место для хранения старых секторов заканчивается, снапшот автоматически исчезает. В VSS, например, для хранения информации об измененных секторах диска используется свободное место на другом диске, что, на мой взгляд, не очень удобно, особенно когда другого диска нет. На мой взгляд, лучше всех реализованы снапшоты у фирмы Storagecraft (http://www.storagecraft.com/products/ vsnap.html), поскольку их технология в виде теневой копии диска не требует дополнительного места на других дисках, как у Microsoft, – вся нужная драйверу информация сохраняется в свободные сектора этого же диска. Кроме того, только у них я встретил режим ColdSnap, который позволяет сделать снимок сразу на этапе загрузки операционной системы – в момент монтирования файловой системы. То есть образ файловой системы (и в том числе системного тома) можно делать так, как это делает Symantec Ghost при загрузке с дискеты или загрузочного CD-ROM.
Нестандартное использование снапшотов
Как это работает Драйвер снапшотов работает как фильтр файловой системы, который пропускает через себя все команды чтения и записи данных на диск. По команде «сделать снимок» драйвер начинает запоминать все изменения, которые производятся на файловой системе, а именно удаление, создание и перезапись файлов и папок. И все. Вся работа по воссозданию копии происходит в момент доступа приложений к этой копии. Драйвер, пользуясь имеющейся у него информацией о том, какие секторы были изменены, подставляет файловой системе снапшота вместо измененных секторов сохраненные старые. Можно смонтировать эту копию как букву диска и делать архивацию любой доступной программой, то есть работать как с любым другим диском. Любая программа архивации теперь может обращаться к снапшоту как к копии диска, на которой все файлы доступны для чтения. Можно сделать снимок сразу на нескольких дисках одновременно. О том, где хранятся старые сектора, знает только драйвер, а
№1, январь 2005
В программе ShadowUser от компании ShadowStor (http:// www.shadowstor.com/products.html) тоже используется идея снапшотов. Здесь появилась возможность смонтировать файловую систему не на реальном диске, а на снапшоте. Этот режим называется ShadowMode. Теоретически снапшоты предназначены только для чтения, но здесь оригинально воплощена идея записи на снапшот. Над образом файловой системы (который сохраняется на жестком диске неизменным) при загрузке устанавливается фильтр файловой
35
безопасность системы. Грубо говоря, в режиме ShadowMode этот фильтр эмулирует новую файловую систему, которая на самом деле не меняет ничего в образе файловой системы на диске, а просто запоминает изменения, которые делают пользователи, программы и другие сервисы ОС. То есть эту новую файловую систему можно сравнить опять же с фотографией, на которой вы можете пририсовать всем усы, но в реальности усов у них не появится. Все изменения пишутся в незанятые сектора, не затрагивая реальную файловую систему. И все эти изменения будут потеряны, как только вы перегрузите компьютер. Можете даже выдернуть питание из компьютера – ничего c настоящей файловой системой не случится, поскольку ее никто не меняет. Драйвер работает так незаметно, что не оставляет своих следов нигде – ни в MBR, ни в таблице разделов, ни во внутренних структурах FAT, FAT32 или NTFS. С точки зрения драйвера снапшотов в режиме ShadowMode дисковое пространство делится на три части: область, занятая файловой системой (таблицы, директории, файлы), область, свободная для записи, и из неё выделяется область, занятая драйвером, в которой хранится информация об измененных секторах. Операционная система и пользователь ничего не знают об этой области и рассматривают две последние области как свободное место. В случае если в процессе работы драйвер займет всё свободное пространство на диске, то возникнет ошибка записи – писать-то некуда. Тут помогает только перезагрузка.
Какие преимущества дает ShadowMode Очень часто администратору или пользователю нужно зафиксировать определенную конфигурацию операционной системы, к которой нужно вернуться в случае сбоев системы. Раньше производилась архивация дисков и последующее восстановление из копии. Теперь эти операции можно делать быстрее и удобнее. Достаточно настроить нужную конфигурацию: установить операционную систему, установить нужные программы и затем перезагрузиться в режим ShadowMode. Все. Теперь реальный диск находится под непробиваемой защитой ShadowMode. Если что-то произошло с операционной системой или просто нужно восстановить чистую конфигурацию, то все, что вам нужно сделать, – это перезагрузиться, и файловая система смонтируется на новом образе реального диска, который на самом деле не изменялся. Можно уже не бояться, что кто-то затер нужную ветку реестра, стер нужный файл или заразил компьютер вирусом. Все будет в идеальном состоянии.
36
Кроме того, при помощи обычной перезагрузки можно избавиться от накопленного за время работы мусора: cookies, файлов истории explorer, spyware, который так и норовит прописаться в домашнюю страничку explorer. Можно даже тестировать другие продукты в этом режиме, чтобы в случае неудачи перезагрузить компьютер и получить очищенную от нового продукта файловую систему. Нужно заметить, что ShadowMode – отличное средство в борьбе администраторов с непослушными пользователями, которые норовят испортить свой компьютер и обвинить во всем администратора. Теперь не нужно долго разбираться, почему что-то исчезло с компьютера или наоборот появилось, – просто пезагрузитесь в новую сессию ShadowMode. Типичные ситуации, когда необходим режим ShadowMode: ! Любое интернет-кафе может успешно использовать эту технологию: для каждого нового клиента операционная система будет выглядеть чистой, словно только что установленная. ! В школах, институтах, различных обучающих центрах: после каждой лабораторной работы легко можно восстановить начальную конфигурацию – для этого нужно просто перегрузить все компьютеры класса. ! Публичные библиотеки могут не бояться пользователей, приходящих со своими дискетами, поскольку в Shadow Mode невозможно записать на диск вирус, а с виртуального диска вирусы стираются обычной перезагрузкой. ! Рабочие места сотрудников различных компаний могут быть навсегда избавлены от вирусов. Не важно, сотрудник ли это банка или туристического агентства. Что ни в коем случае не помешает сохранению полезных данных, которые этот сотрудник создает в процессе своей работы, поскольку можно настроить программу ShadowUser для сохранения этих данных. Читайте далее об этом. ! Сервера, где важно время восстановления после краха. Например, время на восстановление сервера после хакерской атаки, в результате чего было изменено содержимое сайта, равно времени одной перезагрузки! Если веб-сервер при этом записывает различные данные в базу данных, в которой информация должна постоянно пополняться, то можно исключить из ShadowMode директорию, где лежат сами данные – чтобы они были всегда актуальны в случае восстановления всего остального. Нужно заметить, что вы должны обдуманно исключать директории из ShadowMode, поскольку хакеру ничего не помешает воспользоваться этой «дыркой». Для работы с серверами предназначен другой продукт: ShadowServer. В продукте ShadowUser учтено, что пользователь должен хранить где-то свои документы, которые ему не хотелось бы потерять после перезагрузки. Чтобы избежать этого, вы можете добавить некоторые папки в список так называемых исключаемых директорий, и все файлы и содержимое этих директорий будут сохраняться во время работы не на снапшоте, а на реальном диске. Исключать рекомендуется папку, где хранится ваша почта и рабочие документы. Кроме того, можно указать имена исключаемых файлов при помощи маски. Например, укажите *.doc, и все ваши документы Word будут попадать прямо на диск, минуя снапшот. К сожалению, в этом случае на диск будут записаны, в том числе
безопасность и зараженные вирусами документы. Поэтому в случае применения указанной функции антивирус необходим. Я как администратор не стал бы пользоваться этой функцией, а просил бы пользователей хранить документы на файл-сервере, где выполняется антивирусная проверка, архивирование и контролируется доступ к файлам. Однако в течение одной сесии ничего не мешает пользователю редактировать файлы на своем диске. Просто нужно помнить, что после перезагрузки этот файл сотрется.
Если в процессе работы в режиме ShadowMode пользователь обнаруживает, что ему нужно сохранить данные, а он забыл указать какую-то директорию для исключения из снапшота, то есть несколько способов сохранить их. Во-первых, можно, кликнув на нужной папке правой кнопкой и выбрав пункт Commit, переписать данные этой папки со снапшота на реальный диск. Во-вторых, в момент перезагрузки можно скинуть на реальный диск все измененные данные – для этого нужно выбрать опцию Full System Save. Эта операция требует времени, но это лучше, чем потерять работу, сделанную за день. Администратор может запретить пользователю эту операцию, установив пароль.
Выводы У системных администраторов появилась отличная утилита, упрощающая их жизнь. Теперь на любой звонок, что чтото не работает, можно отвечать одним словом «перезагрузитесь» и быть в полной уверенности, что все будет работать так, как вы настроили когда-то давно. Вся прелесть в том, что даже если упадет сам Windows, то после перезагрузки будет эффект восстановления из архива – Windows запустится как ни в чем не бывало, вдобавок рабочие документы и почта будут спасены (естественно, если они были в списке исключаемых). У преподавателей исчезает головная боль с настройкой каждого компьютера перед занятиями, и уже можно безбоязненно давать портить операционную систему юным хакерам. Выключить ShadowMode они не смогут, поскольку для этого нужно знать пароль. Даже если пользователи каким-то образом получат права администратора, то тоже ничего не смогут изменить, поскольку выключить ShadowMode можно только перезагрузкой, а тут есть риск наткнуться на пароль BIOS, и к учителю все равно придется обращаться. Несомненным плюсом программы является уменьшение стоимости владения. Если хранить документы только на файл-сервере, то кажется сомнительной необходимость ан-
№1, январь 2005
тивирусного программного обеспечения на рабочей станции, которое требует ежедневного обновления сигнатур вирусов через Интернет. Получается, что можно как минимум сэкономить на ежегодной подписке на базы, да и на трафике. Становится легче обслуживать Windows: достаточно один раз и навсегда все установить, настроить и включить ShadowMode. Можно на этот случай воспользоваться услугами стороннего администратора. К сожалению, это не защищает от уязвимостей, которые до сих пор находят (и, вероятно, будут находить) в Windows, поэтому обновлять операционную систему периодически придется. Но даже если имеющиеся уязвимости будут как-то использованы злоумышленником, то ему сложно будет установить и затем воспользоваться программой удаленного управления, сниффером или трояном на уязвимой рабочей станции, поскольку все это будет жить до следующей перезагрузки. Даже если вирус сможет разрушить файловую систему, то это также вылечится перезагрузкой. На мой взгляд, фраза на сайте www.shadowstor.com о том, что «ShadowUser полностью избавляет от новых вирусов», не совсем точна. Действительно, раньше не было утилиты, которая бы могла удалить любой новый вирус, который еще неизвестен антивирусу. Программа ShadowUser в силу своей природы делает это обычной перезагрузкой компьютера. Но существует другая опасность, что во время сессии ShadowMode зараженный компьютер может являться сам источником вируса или компьютерного червя. Уже были случаи, когда компьютер, зараженный компьютерным червем, сканировал соседние компьютеры и заражал их по сети без участия пользователя, пользуясь ошибками переполнения буфера сетевых служб. Так делали в свое время черви Sasser, Kibuv и Lovesan, пользуясь ошибками в LSASS и DCOM RPC Windows. В результате, перезагружая по очереди несколько зараженных в сети компьютеров, даже защищенных ShadowMode, мы просто будем перекидывать червя с одного компьютера на другой, а полного лечения не добьемся, пока не выключим все компьютеры. Таким образом, ShadowUser лишь очередная преграда на пути новых вирусов, но не последняя. К сожалению, антивирусы тоже плохо сдерживают вирусные эпидемии, поскольку антивирусные компании как правило выпускают обновленные базы сигнатур новых вирусов уже после начала эпидемии. Хочется заметить также, что не совсем верна фраза: «Вся информация пропадает после перезагрузки». Для продвинутого пользователя не очень сложно посмотреть, что находится в свободных секторах, не занятых файловой системой. Ведь именно в них хранится та информация, которая была записана в прошлую сессию ShadowMode. Я думаю, что в продукт необходимо добавить процедуру заполнения этих мест нулями после окончания каждой сессии ShadowMode. Мне часто бывает интересно узнать, что было изменено на диске после установки какой-либо программы на компьютер. Пока я пользуюсь утилитой Sysinternals Filemon, которая показывает список файлов, к которым обращались процессы. Мне очень не хватает утилиты для изучения и сравнения изменений файловой системы «до» и «после». Хотелось бы от программ, реализующих технологию снапшотов, получить такую функциональность. Надеюсь, эта функция тоже скоро будет реализована.
37
безопасность
КАК ЗАЩИЩАЮТ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ …Важно не только научиться. Важно не научиться. Не научиться бывает подчас трудней. Нарушить стандарт, отвергнуть шаблон. Не принять общепринятого. Л. Озеров «Выбор и предпочтение»
Потребность в защитных механизмах растет с каждым днем, но качество их реализации падает вниз стремительным домкратом. Давным-давно сломан HASP, FLEX LM, ASProtect и другие широко разрекламированные решения, лишний раз подтверждая, что вы не можете доверять никакому коду, кроме своего собственного, но что делать, если вы и в себе не уверены? Эта статья перечисляет основные ошибки, совершаемые разработчиками, и дает советы по усилению защиты.
КРИС КАСПЕРСКИ В борьбе за выживание защитные механизмы обречены. Защита лишь продлевает мучения программы, отодвигая ее взлом на некоторый срок. Теоретически. Практически же ничего не стоит создать защиту, позволяющую программе дожить до преклонных лет и «умереть» собственной смертью, передавая наследие следующей версии. Главное – правильно забаррикадироваться. Бессмысленно вешать стальную дверь на картонный дом. Линия обороны должна быть однородна во всех направлениях, поскольку стойкость защиты определяется наиболее уязвимой ее частью. Мы не будем касаться вопросов целесообразности защиты как таковой (это отдельный больной вопрос), а сразу перейдем к рекомендациям, следование которым усилит защиту настолько, насколько это возможно. Необходимо не только добиться экономической нецелесообразности взлома, но и убить моральный стимул к хакерству «на интерес» – для этого защита должна быть максимально «тупой», а ее взлом – рутинным. Выбирайте только надежные, системно-независимые методики. Хитроумные антиотладочные приемы только разжигают хакерский интерес, и что еще хуже – выдают ложные, срабатывая у легальных пользователей, а этого допускать ни в коем случае нельзя. Делайте ставку на частый выход новых версий и техническую поддержку – это оттолкнет пользователей от «кракнутых» версий.
Джинн из бутылки, или недостатки решений из коробки Зачем изобретать велосипед, когда на рынке представлено множество готовых решений – как программных (ASProtect, FLEX LM, Extreme Protector), так и аппаратных (HASP, Sentinel, Hardlock)? Ответ – стойкость защиты обратно пропорциональна ее распространенности, особенно если она допускает универсальный взлом (а все вышеперечисленные решения его допускают). Даже начинающий хакер, скачавший руководство по борьбе с HASP, за короткое время «отвяжет» программу, особенно если защита сводится к тривиальному: if (IsHaspPresent() != OK) exit();
38
Защитный механизм должен быть глубоко интегрирован в программу, тесно переплетен с ней. Все, что быстро защищается, быстро и ломается! Хуже всего то, что многие протекторы содержат грубые ошибки реализации, нарушающие работоспособность защищаемой программы или даже всей операционной системы вызывающим поведением (например, Armadillo замусоривает реестр, замедляя работу системы, и это никак не отражено в документации!) Защищая программу самостоятельно, вы тратите силы и время, но зато получаете предсказуемый результат. «Фирменный» защитный механизм – кот в мешке, и неизвестно, какие проблемы вас ждут.
От чего защищаться Чаще всего программы защищают от несанкционированного копирования, ограничения времени испытательного использования, реконструкции оригинального алгоритма и модификации файла на диске и памяти.
Защита от копирования, распространения серийного номера От несанкционированного копирования в принципе защищает привязка к машине (как это сделать с прикладного уровня, см. в статье [1]). «В принципе» потому, что пользователям очень не нравится, когда ограничивают их свободу, поэтому привязывайтесь только к носителю (лазерному диску). Нет никакой необходимости выполнять проверку при каждом запуске программы, требуя наличия диска в приводе (а сможет ли ваша программа «увидеть» его по сети?), достаточно проверки на этапе инсталляции. Не надо бояться, что это ослабит защиту – в любом случае при наличии ключевого диска, программа отвязывается элементарно. Цель «привязки» – противостоять не хакерам, а пользователям. О том, как создать диск, не копируемый копировщиками защищенных дисков (Alcohol, CloneCD), можно прочитать в [2] или [3] . Пусть защита периодически «стучится» в Интернет, передавая вам серийный номер. Если один и тот же серийный номер будет поступать со многих IP-адресов, можно передать удаленную команду на дезактивацию «флага» ре-
безопасность гистрации (удалять файл с диска категорически недопустимо!). Только не возлагайте на этот механизм больших надежд – пользователь может поставить брандмауэр (правда, локальные брандмауэры легко обойти, см. [4]) или же вовсе работать на машине, изолированной от сети. Защита серийным номером (далее по тексту – s/n) не препятствует несанкционированному копированию, но если все серийные номера различны, можно вычислить пользователя, выложившего свой s/n в сеть. То же самое относится и к парам имя пользователя/код активации (далее по тексту – u/r). Идея: пусть сервер генерирует дистрибутивный файл индивидуально на основе регистрационных данных, переданных пользователям. Тогда его u/r не подойдет к чужим файлам и весь дистрибутив придется выкладывать в сеть целиком, что намного проблематичней, и к тому же далеко не каждый пользователь рискнет скачивать двоичный файл из ненадежных источников.
Защита испытательным сроком При защите «испытательным сроком» никогда не полагайтесь на системную дату – ее очень легко перевести «назад». Сравнивайте текущую дату с датой последнего запуска программы, сохраненной в надежном месте, помня о том, что не всякое расхождение свидетельствует о попытке взлома – может, это пользователь поправляет неверно идущие часы. Используйте несколько независимых источников – отталкивайтесь от даты открываемых файлов (или в общем случае – файлов, обнаруженных на компьютере пользователя), подключайтесь к службе атомного времени (если доступен Интернет) и т. д. Для предотвращения деинсталляции/повторной инсталляции никогда не оставляйте никаких «скрытых» пометок в реестре или файловой системе. Во-первых, «уходя, заметай следы», а во-вторых, пользователь может запускать вашу программу из-под эмулятора ПК (Microsoft Virtual PC, VM Ware), – современные аппаратные мощности это уже позволяют. Он просто переформатирует виртуальный диск, уничтожая все следы пребывания вашей программы. Сохраняйте количество запусков в обрабатываемых программой документах (естественно, в нетривиальном формате, который непросто подправить вручную). Противостоять этому очень трудно! Вообще лучшая защита демонстрационных версий – физическое усечение функциональности с удалением программного кода, отвечающего, например, за печать или сохранение файла.
Защита от реконструкции алгоритма Чтобы хакер не смог реконструировать алгоритм защитного механизма и слегка «доработать» его напильником (или же попросту «подсмотреть» правильный пароль), обязательно используйте многослойную динамическую шифровку по s/n или u/r. Тогда без s/n, u/r взлом программы станет невозможным. Не проверяйте CRC s/n! Чтобы убедиться в правильности ввода s/n, проверяйте CRC расшифрованного кода (восстановить исходный s/n по его CRC на достаточных аппаратных мощностях вполне возможно, но CRC расшифрованного кода криптоаналитику вообще ни о чем не
№1, январь 2005
говорит!). Игнорируйте первые четыре символа s/n, посадив на них подложный расшифровщик – обычно хакеры ставят точку останова на начало s/n, но не на его середину. Еще лучше, если каждый из нескольких расшифровщиков будет использовать «свою» часть s/n. Спрашивайте имя, компанию, прочие регистрационные данные, делайте с ними сложные манипуляции, но никак их не используйте – пусть хакер сам разбирается, какие из них актуальные, а какие нет. Шифровка называется динамической, если ни в какой момент весь код программы не расшифровывается целиком, в противном случае хакер может снять с него дамп, и привет! Расшифровывайте функцию перед вызовом, а по выходу из нее – зашифровывайте вновь. Используйте несколько независимых шифровщиков и перекрытия шифроблоков, иначе хакер расшифрует программу «руками» самого расшифровщика, просто передавая ему номера/указатели зашифрованных блоков, и сбросит дамп. Многословная шифровка: делаем на каждом «слое» что-то полезное, затем расшифровываем следующий слой и т. д. Программный код как бы размазывается между слоями, вынуждая хакера анализировать каждый из них. Если же весь программный код сосредоточен в одном-единственном слое, количество слоев шифровки, «оборачивающих» его, не имеет никакого значения и ничуть не усложняет взлом. Разбавляйте защитный код (и в особенности код расшифровщика) большим количеством мусорных инструкций – процедуру размером в 1 Мбайт за разумное время дизассемблировать практически нереально. Мусор легко генерировать и автоматически (ищите в вирусных журналах полиморфные движки) – следите только за тем, чтобы визуально он был неотличим от полезного кода. Еще лучший результат дают виртуальные машины, выполняющие элементарные логические операции (Сети Петри, Стрелка Пирса, Машина Тьюринга). Даже если хакер напишет декомпилятор, на реконструкцию алгоритма уйдет вся оставшаяся жизнь (подробнее см. [5]). При использовании однослойной шифровки размазывайте расшифровщик по телу программы, никогда не располагайте весь код расшифровщика в конце модуля – тогда переход на оригинальную точку входа может быть распознан по скачкообразному изменению регистра EIP. Кстати, стартовый код, внедряемый компиляторами в программу, в большинстве случаев начинается с обращения к FS:[0] (регистрация собственного обработчика исключений) – почаще обращайтесь к этой ячейке из расшифровщика, не позволяя хакеру быстро определить момент завершения расшифровки (вызовы должны следовать из разных мест, иначе хакер просто наложит фильтр, благо современные отладчики это позволяют). Обязательно привязывайтесь к начальному значению глобальных инициализированных переменных, т. е. поступайте так: FILE *f = 0; main(){if (!f) f = fopen(,,)…}
тогда дамп, снятый вне оригинальной точки входа, окажется неработоспособным. Дизассемблируете стандартный «Блокнот» – он именно так и устроен.
39
безопасность Защита от модификации на диске и в памяти Модификацию кода предотвращает проверка целостности, причем следует проверять как целостность самого файла, так и целостность дампа в памяти (хакер может модифицировать программу на лету, или даже ничего не модифицировать, а на время перехватить управление и проэмулировать несколько следующих команд, или же просто изменить значение регистра EAX после выполнения команды типа TEST EAX, EAX или подобной ей). Перехвату управления/эмуляции противостоять практически невозможно, а вот предотвратить модификацию легко – используйте несистематические коды Рида-Соломона (см. [6]). Чтобы взломать программу, хакеру потребуется не только разобраться, какие именно байты следует подправить для взлома программы, но и рассчитать новые коды РидаСоломона, а для этого ему придется написать собственный кодировщик, что не так-то просто (несистематическое кодирование изменяет все кодируемые байты, в отличие от систематического кодирования, где к программе просто дописывается «контрольная сумма», проверка которой может быть легко «отломана»). Опять-таки это актуально только для многослойной динамической шифровки, в противном случае хакер просто дождется завершения декодирования кодов Рида-Соломона и снимет беззащитный дамп. Как вариант используйте несимметричные криптоалгоритмы. Это предотвратит модификацию файла на диске (но не в памяти!), и, что еще хуже, зашифровка функции по выходу из нее оказывается невозможной (мы ведь не хотим сообщать хакеру секретный ключ?), а значит, код программы рискует в какой-то момент оказаться расшифрованным целиком. Чтобы этого не произошло, расшифровывайте код функции во временный буфер (общий для всех функций), не трогая оригинал. Проверяя целостность кода, не забывайте о перемещаемых элементах. Если программа/динамическая библиотека будет загружена по адресу, отличному от указанного в PEзаголовке, системный загрузчик автоматически скорректирует все ссылки на абсолютные адреса. Либо избавьтесь от перемещаемых элементов (ключ /FIXED линкера MS Link), либо, что лучше, проверяйте только ячейки, не упомянутые в relocation table. Никогда не блокируйте некоторые пункты меню/кнопки для ограничения функциональности демонстрационной версии – их не разблокирует только ленивый! Лучше физически вырезайте соответствующий код или на худой конец время от времени проверяйте состояние заблокированных элементов управления, т.к. они могут быть разблокированы не только в ресурсах, но и динамически – отправкой сообщения окну.
От кого защищаться Арсенал современных хакеров состоит преимущественно из: дизассемблера, отладчика, дампера памяти и монитора обращений к файлам/реестру. Это очень мощные средства взлома, но с ними все-таки можно справиться.
Антидизассемблер Дизассемблер – в девяти из десяти случаев это IDA Pro. Существует множество приемов, приводящих ее в замешатель-
40
ство («ее» – потому, что Ида женское имя): множественные префиксы, искажение заголовка PE-файла и т. д., однако смысла в них немного, и многослойной шифровки на пару с мусорным кодом для ослепления дизассемблера вполне достаточно (правда, опытные хакеры могут написать плагин, автоматизирующий расшифровку и вычищающий мусорный код, но таких единицы, и вы можете гордиться, что ломались у них). Кстати говоря, активное использование виртуальных функций в С++ существенно затрудняет дизассемблирование программы, поскольку для определения эффективных адресов приходится выполнять громоздкие вычисления или «подсматривать» их в отладчике (но про борьбу с отладчиками мы еще поговорим). Только помните, что оптимизирующие компиляторы при первой возможности превратят виртуальные функции в статические.
Антиотладка Еще ни одному из отладчиков не удалось полностью скрыть свое присутствие от отлаживаемой программы, и потому он может быть обнаружен. Чаще всего используется сканирование реестра и файловой системы на предмет наличия популярных отладчиков, проверка флага трассировки, чтение содержимого отладочных регистров/IDT, замер времени выполнения между соседними командами и т. д. (если хотите узнать больше, наберите «anti-debug» в Google). Однако запрещать пользователю иметь отладчик категорически недопустимо – защита должна реагировать лишь на активную отладку. К тому же все эти проверки элементарно обнаруживаются и удаляются. Надежнее трассировать самого себя, подцепив на трассировщик процедуру расшифровки или генерировать большое количество исключительных ситуаций, повесив на SEH-обработчики процедуры, делающие что-то полезное. Попутно: оставьте в покое softice – в хакерском арсенале есть и альтернативные отладчики. Эмулирующим отладчикам противостоять труднее, но ничего невозможного нет. Используйте MMX-команды, сравнивая время их выполнения со временем выполнения «нормальных» команд. На живом процессоре MMX-команды работают быстрее. Отладчики же либо вообще не эмулируют MMX-команд, либо обрабатывают их медленнее нормальных команд.
Антимонитор Мониторы – очень мощное хакерское средство, показывающее, к каким файлам и ключам реестра обращалась защищенная программа. Активному мониторингу в принципе можно и противостоять, но лучше этого не делать, ведь существует и пассивный мониторинг (снятие слепка с реестра/файловой системы и сравнение его до и после запуска программы), а против него не пойдешь. Не храните регистрационную информацию в явном виде. Забудьте о флагах регистрации! Вместо этого размазывайте ключевые данные маленькими кусочками по всему файлу, считывайте их в случайное время из случайных мест программы, расшифровывая очередной кусок кода. Вместо fopen/fseek/fread используйте файлы, проецируемые в память, они намного сложнее поддаются мониторингу, но это уже тема отдельного разговора.
безопасность Антидамп Дамперам противостоять проще простого. Их много разных, но нет ни одного по-настоящему хорошего. Затирайте PE-заголовок в памяти (но тогда не будут работать функции типа LoadResource) или по крайней мере его часть (о том, какие поля можно затирать, читайте в [7]). Выключайте временно неиспользуемые страницы функцией Virtual Protect(.,PAGE_NOACCES,), а перед использованием включайте их вновь. Впрочем, хакер может уронить NT в «синий экран», получив образ подопытного процесса в свое распоряжение. Однако при использовании динамической многослойной шифровки толку от этого образа будет немного.
Как защищаться Никогда не давайте хакеру явно понять, что программа взломана! Тогда ему остается найти код, выводящий ругательное сообщение (а сделать это очень легко) и посмотреть, кто его вызвал – вот сердце защитного механизма и локализовано. Используйте несколько уровней защиты. Первый – защита от ввода неправильного s/n и непредумышленного нарушения целостности программы (вирусы, дисковые сбои и т. д.). Второй – защита от хакеров. Обнаружив факт взлома, первый уровень «ругается» явно, и хакер быстро его нейтрализует, после чего в игру вступает второй, время от времени вызывающий зависания программы, делающий из чисел «винегрет», подменяющий слова при выводе документа на принтер и т. д. При грамотной реализации защиты нейтрализация второго уровня потребует полного анализа всей программы. Да за это время можно десять таких программ написать! Второй уровень никогда не срабатывает у честных пользователей, а только у тех, кто купит «крак». Если же вы боитесь, что второй уровень случайно сработает в результате ошибки, лучше вообще не беритесь за программирование, это не для вас. Не показывайте хакеру, каким путем регистрируется защита. Это может быть и ключевой файл, и определенная комбинация клавиш, и параметр командной строки. Ни в коем случае не считываете s/n или u/r через WM_GETTEXT/ GetWindowText, вместо этого обрабатывайте нажатия одиночных клавиш (WM_CHAR, WM_KEYUP/WM_KEYDOWN), прямо из основного потока ввода данных, и тут же их шифруйте. Смысл шифровки в том, чтобы вводимая пользователем строка нигде не присутствовала в памяти в явном виде (тогда хакер просто поставит на нее точку останова, и могучий soft-ice перенесет его прямо в самый центр защитного механизма). Интеграция с основным потоком ввода предотвращает быстрый взлом программы. Точка останова на WM_XXX ничего не дает, поскольку не позволяет быстро отличить обычные вводимые данные от s/n. Возьмите на вооружение генератор случайных чисел – пусть проверки идут с разной периодичностью из различных частей программы (использовать общие функции при этом недопустимо – перекрестные ссылки и регулярный поиск выдадут вас с головой!). Не используйте функцию rand() – вместо этого отталкивайтесь от вводимых данных, преобразуя в псевдослучайную последовательность задержки между нажатиями клавиш, коды вводимых символов, последовательность открытий меню и т. д.
№1, январь 2005
Ни в коем случае не храните «ругательные» строки открытым текстом и не вызывайте их по указателю – хакер мгновенно найдет защитный код по перекрестным ссылкам. Лучше так: берем указатель на строку, увеличиваем его на N байт. Сохраняем указатель в программе, а перед использованием вычитаем N на лету (при этом вам придется сражаться с коварством оптимизирующих компиляторов, норовящих вычесть N еще на стадии компиляции). Избегайте прямого вызова API-функций. Наверняка хакер поставит на них точку останова. Используйте более прогрессивные методики – копирование API-функций в свое тело, вызов не с первой машинной команды, распознание и дезактивация точек останова (подробности в «Записках мыщъх’а». Солон-Р, 2004 г.). Разбросайте защитный механизм по нескольким потокам. Отладчики не выполняют переключение контекста, и остальные потоки просто не получат управление. Кроме того, очень трудно разобраться в защитном механизме, исполняющимся сразу в нескольких местах. Создайте несколько подложных функций, дав им осмысленные имена типа CheckRegisters, – пусть хакер тратит время на их изучение!
Заключение Можно уметь ломать программы, не умея их защищать, а вот обратное утверждение неверно. Это не вопрос морали, это вопрос профессиональных навыков (закон разрешает «взлом», если он не влечет за собой прочих нарушений авторских и патентных прав). Теория – это хорошо, но в машинных кодах все не так, как на бумаге, и большое количество взломов свидетельствует отнюдь не о всемогуществе хакеров, а о катастрофической ущербности защитных механизмов, многие из которых ломаются за считанные минуты! Личное наблюдение – за последние несколько лет качество защит ничуть не возросло. Причем если раньше творчески настроенные программисты активно экспериментировали со своими идеями, то сейчас все больше склоняются к готовым решениям. Хотелось бы, чтобы эта статья послужила своеобразным катализатором и подтолкнула вас к исследованиям.
Литература: 1. Мешков В. Пакетные команды интерфейса ATAPI. – Журнал «Системный администратор», №9, сентябрь 2004 г. 2. Касперски К. Техника защиты CD. БХВ-Петербург, 2004 г. 3. Касперски К. Искажение TOC как средство борьбы с несанкционированным копированием диска. – Журнал «Системный администратор», №9, сентябрь 2003 г. 4. Касперски К. Побег через брандмауэр плюс терминализация всей NT. – Журнал «Системный администратор», №5, май 2004 г. 5. Касперски К. Техника и философия хакерских атак. Солон-Р, 2005 г. 6. Касперски К. Коды Рида-Соломона в практических реализациях, или информация, воскресшая из пепла III. – Журнал «Системный администратор», №11, октябрь 2003 г. 7. Касперски К. Путь воина – внедрение в pe/coff-файлы. – Журнал «Системный администратор», №6, июнь 2004 г.
41
безопасность
СЕТЕВОЙ ПОЛИЦЕЙСКИЙ The bad packets stop here!
СЕРГЕЙ ЯРЕМЧУК В необходимости защиты компьютеров в сети сегодня убеждать, наверное, никого уже не надо. Вопрос обычно состоит в выборе того или иного инструмента для этих целей. Для организации брандмауэра в небольших и средних фирмах редко покупают отдельное устройство. Для таких фирм фактор цены обычно стоит на первом месте, и поэтому они стараются по возможности использовать б/у компьютеры, которые обычно имеются не в единственном числе. Об одном из удобных дистрибутивов, который можно использовать на таком оборудовании, и пойдет речь в статье. IPCop (http://www.ipcop.org) представляет собой базирующуюся на GNU/Linux систему, которая может быть использована для построения брандмауэра как в небольших домашних сетях, так и в сетях предприятий. Это его основное назначение. Но кроме организации межсетевого экрана, инструменты, входящие в IPCop, позволяют: ! регулировать входящий и исходящий трафик; ! наблюдать за событиями, происходящими в сети; ! предупреждать о нападении;
42
! организовать виртуальную частную сеть (Virtual private ! ! ! !
network – VPN), которая позволяет безопасно соединять сети через Интернет; назначать компьютерам IP-адреса посредством DHCP; синхронизировать время, используя NTP; кэшировать веб-страницы и данные службы DNS; выдавать информацию об использовании системных ресурсов.
Дополнительно ко всему удобно и просто конфигурировать систему посредством веб-интерфейса. Для работы достаточно компьютера с процессором 386 с 32 Мб ОЗУ и 300 Мб жесткого диска. Это, естественно, минимальные требования. При организации кэширования веб-страниц и регистрации сетевых событий, а также в больших сетях требования к оборудованию возрастают. Для инсталляции потребуются клавиатура и монитор (для удобства и мышь), после чего их можно отключить. Гибкий диск на компьютере не требуется, но будет полезен при ко-
безопасность пировании настроек и обновлении системы. Забегая вперед, скажу, что имеется скрипт http://www.timbutterfield.com/ computer/ipcop/backup, позволяющий производить эту операцию через сеть. Можно обойтись даже без CD-ROM и установить дистрибутив, используя http. IPCop может быть установлен и на Compact Flash, в руководстве по установке есть упоминания по этому поводу. Ядром поддерживаются некоторые PCMCIA-, SCSI- и USB-устройства, список протестированого оборудования можно найти в «IPCop Hardware Compatibility List». Кроме того, начиная с версии 1.4.0, кроме Intel-архитектуры, поддерживаются и Аlpha-процессоры. Помимо основного сайта дополнительную информацию об IPCop можно получить и на других сайтах – http:// www.ipcops.net, http://sourceforge.net/projects/ipcop.
Установка IPCop Несмотря на такие большие возможности, дистрибутив получился довольно компактным, чуть меньше 40 Мб. Перед установкой разработчики настоятельно рекомендуют почитать инструкцию по установке, которую можно найти как на сайте проекта, так и в установочном iso-образе, полученном с сайта. Весь процесс не должен занять больше 10-15 минут времени. Но главное, помните, что все данные на используемом жестком диске будут уничтожены, т.к. программа установки автоматически создает разделы. Для удобства работы предусмотрено использование четырех сетевых устройств: ! Red – опасное интернет-соединение.
№1, январь 2005
! Green – безопасная внутренняя сеть. ! Orange – DMZ (De-Militarized Zone) для серверов, которые должны быть доступны из Интернета.
! Blue – беспроводная полудоверенная сеть (до версии 1.3.0 wireless-сети выводились либо в Green-, либо в Orangeзоны). Процесс установки происходит в графической среде с понятными подсказками и минимальным участием пользователя. Единственное, что в списке из более 20 языков, доступных при установке, нет русского, может, это кому-то покажется неудобным, уже после установки можно выбрать русский. А так выбираем источник установки, далее программа предупреждает об уничтожении данных на жестком диске, после чего создаются разделы с файловой системой, копируются данные, и если есть сохраненная на дискете конфигурация, то можно восстановить настройки. Следующим шагом настраиваются сетевая «Green-карта», клавиатурная раскладка, часовой пояс, имя компьютера в сети, параметры ISDN, использование DHCP на Green-интерфейсе, вид сетевой конфигурации (например, green + orange + red) и настраиваются остальные сетевые устройства, устанавливаются пароли для пользователей root и admin, после чего система перезагружается. Теперь все дальнейшие настройки производятся, используя SSH (в версии 1.4.1 вместо 22 порта почему-то используется 222) или через веб-интерфейс. Для удобства администрирования системы при помощи командной строки предусмотрена программа /usr/local/sbin/
43
безопасность setup, которая поможет малоопытному пользователю не запутаться в неизвестных командах. Запустив ее, при помощи меню можно выполнить большую часть необходимых операций: изменить раскладку клавиатуры, имя узла и домена, пароли пользователей, сетевые настройки. Если в вашем распоряжении только компьютеры под управлением Windows, в составе которых нет необходимых утилит для удаленного доступа по SSH, в таком случае можно воспользоваться свободными утилитами вроде PuTTY (http:// www.chiark.greenend.org.uk/~sgtatham/putty) или WinSCP (http://winscp.sourceforge.net/eng/). Какую из них использовать – дело вкуса, мне больше нравится WinSCP, к тому же он доступен и в виде плагина к FAR. Набрав на другом компьютере из внутренней сети в строке браузера: http://Green _address:81/
при этом вызов будет перенаправлен на защищенное соединение https://Green _address:445 (его также можно использовать). Далее регистрируемся как пользователь admin и получаем возможность настроить все необходимые параметры посредством веб-интерфейса. Для удобства восприятия в System – GUI Setting можно выбрать русский язык интерфейса (примечание: после этого программа /usr/local/sbin/ setup откажется работать, ссылаясь на недопустимый язык системы). Пользователю доступны семь вкладок («Система», «Состояние», «Сеть», «Службы», «Файервол», «ВЧС»
44
и «Логи») с подпунктами в каждой. Так, в меню «Система» можно скачать обновления нажатием одной кнопки, изменить пароли, настроить доступ по SSH, сохранить настройки на дискету, выключить маршрутизатор и ознакомиться с создателями. В меню «Состояние» – получить данные и графики о работе системы (запущенные сервисы и загруженные модули, состояние памяти и заполнение дисковых разделов и пр.), сети (в том числе таблицы маршрутизации и трассировка связи по IPTables). В подпунктах вкладки «Сеть» указываются параметры модемного соединения (только для RED). В меню «Службы» выбираются параметры и запускаются: прокси-сервер Squid и DNS-сервера, DHCP-сервер для Green-интерфейса, параметры предпочтительных Network Time Server, выставить приоритеты сервисов, включить использование NIDS Snort для тех сетевых интерфейсов, где хотите контролировать происходящее. В этом же пункте можно занести данные об IP-адресах и именах известных узлов в файл /etc/hosts, для того чтобы лишний раз не обращаться к DNS-серверам. Если необходимо запретить доступ к некоторым сайтам, то самым простым решением будет занести в этот же файл приблизительно такую конструкцию, вставив нужное имя (список некоторых «ненужных» сайтов можно найти по адресу http://ssmedia.com/utilities/hosts). 0.0.0.0 0.0.0.0
www. Site_1.com www. Site_2.org
Во вкладке «Файервол» всего два пункта. В одном из
безопасность них выставляются параметры перенаправления портов, во втором задаются правила iptables для внешнего сетевого интерфейса (по умолчанию очень строгие). В «ВЧС» в удобной и понятной форме можно указать параметры VPN-соединения OpenSWAN, для чего необходимо просто заполнить пункты, указав IP-адреса, вид соединения (Host-to-Net, Net-to-Net) и выбрать/создать сертификат. И наконец, во вкладке «Логи» получить доступ к журналам приложений, при этом возможен просмотр событий по дням, месяцам и экспорт. Разобраться с настройкой системы при помощи вышеуказанных меню, думаю, особого труда не составит. Если что, на сайте имеются подробные руководства (на английском языке) по администрированию IPCop и настройке VPN.
Расширение возможностей IPCop Как бы там ни было, но несмотря на довольно неплохие возможности этого дистрибутива, через некоторое время администратору, скорее всего, захочется их расширить. В принципе админ с опытом работы в UNIX-системах сам способен добавить необходимые компоненты, но IPCop ориентирован именно на легкость в использовании, в том числе и на неопытного пользователя. В расширении возможностей системы может помочь документ «IPCop Addons» (http://ipcop.org/ cgi-bin/twiki/view/IPCop/IPCopAddons), в котором даны ссылки и краткие описания всех проектов и скриптов, так или иначе связанных с добавлением функциональности этому дистрибутиву. Первый проект, на который удалось выйти (Unofficial) IPCop Firewall Addon Server (http://firewalladdons.source forge.net/index.html), располагает рядом инструментов, позволяющих существенно нарастить функциональность IPCop, в основном между Red- и Green-интерфейсами. При этом работать с предлагаемыми расширениями под силу и новичку, имеющему некоторые навыки удаленного администрирования. Пакеты рассортированы по девяти группам (Proxy Servers, Entertainment, VPN, Servers, Utilities, Logging, Modems/NICS, Miscellanous, Language PAKS). Из необходимого хочется отметить наличие контекстного фильтра Cop+, построенного на основе Dansguardian с автоматической закачкой «черных списков» (есть еще SquidGuard, но он долго не обновлялся). Далее MOD BlockOutTraffic позволяет блокировать исходящий трафик для Blue-интерфейса, руководствуясь прописанными IP- и MAC-адресами, а еще Nmap и IPTraf, без которых тяжелее организовать нормальное администрирование сети, для улучшения безопасности подойдет DSLogcheck и Tripwire. И еще много различных MOD, в том числе такие как редактор Joe и Midnight Commander. Все пакеты, имеющие префикс GUI в названии, будут доступны после установки через веб-интерфейс, CLI только из консоли. При установке следует также обращать внимание на версии Addon-сервера и IPCop, для которого был написан MOD, хотя, возможно, некоторые утилиты удастся заставить работать и с другой версией. С MOD управляться очень просто и легко. Первым делом скачиваем сам Аddon-сервер, на момент написания статьи это была версия 2.2, т.е. пакет addons-2.2-CLI-b2.tar.gz. Переносим этот пакет при помощи SSH или дискетой, затем распаковываем и устанавливаем.
№1, январь 2005
# tar vxzf addons-2.2-CLI-b2.tar.gz -C / # cd /addons # ./setup –u èëè ./setup –i
Теперь если посмотреть на веб-браузер, то обнаружится еще одна вкладка – ADDONS, являющаяся менеджером установленных MOD, плюс отсюда же можно закачать на IPCop необходимые MOD. Сами же MOD устанавливаются аналогично серверу, после чего в соответствующих вкладках появится дополнительный подпункт. Как создать свой MOD, довольно подробно описано в документе «How to write your own MOD». Из других полезных, на мой взгляд, утилит расширения стоит обратить также внимание на linetest (http://alquanto.de/ goodies/linetest), который позволяет автоматически переключаться на резервное соединение в случае пропадания основного канала. Если же просто нужно перезапустить соединение, то в «IPCop Addons» приведены примеры скриптов. Большое количество различных скриптов расширения, в том числе для подсчета трафика, вывода различных диаграмм, дополнения для squid, найдете по адресу www.zpdee.net/~joecat. Для проверки входящей почты на предмет наличия вирусов и спама используйте комплект Copfilter (http://www.madlener.tk), включающий в себя такие приложения, как spamassassin, clamscan и пр. В общем, можно существенно повысить функциональность системы. Чтобы гарантировать всестороннюю и глубокую защиту, необходимо иметь сетевые и узловые решения на каждом устройстве. Такой подход не всегда приемлем как с точки зрения удобства, так и конечной стоимости такого подхода. Дистрибутивы, подобные IPCop, представляют собой более всестороннее решение этого вопроса, позволяя защитить внутренние сети при помощи брандмауэра. Расширенные возможности вроде сетевой системы обнаружения атак, возможности организации виртуальной частной сети вкупе с легкостью настройки, локализацией, надежностью решения и возможности наращивания системы делают IPCop весьма привлекательным решением, управиться с которым может и новичок в администрировании.
Уважаемые читатели! Продолжается подписка на журнал на I-полугодие 2005 года. Если вы не успели подписаться на все шесть выпусков следующего полугодия, вы сможете приобрести недостающие номера через интернет-магазины
Доставка почтой в любую точку России.
45
безопасность
ЗАЩИТА СЕТЕВЫХ СЕРВИСОВ С ПОМОЩЬЮ stunnel ЧАСТЬ 2
АНДРЕЙ БЕШКОВ В первой части статьи мы говорили о том, как защищать сервисы с помощью программы stunnel. SSL-шифрование данных выполняется посредством OpenSSL. Как обычно, все, о чем шла речь, работало под управлением FreeBSD 4.10. Чтобы проверить, как эта конструкция будет жить на пятой ветке, я перенес тестовое окружение на FreeBSD 5.3. Так что теперь мы будем работать на этой платформе. Процедура установки и настройки практически ничем не отличается от того, что было описано в первой части статьи, если, конечно, следовать официально рекомендованному пути и ставить все из портов. Продолжим рассмотрение новых способов применения stunnel. На предложение шифровать http-трафик с помощью stunnel большинство читателей, cкорее всего, посмотрит на меня с некоторой долей удивления во взгляде, а кое кто, возможно, даже покрутит пальцем у виска. А ведь они частично правы. Зачем использовать внешнюю утилиту,
46
если для этой задачи у нас есть отлично работающий Apache и mod_ssl? Но все же не Apache единым жив администратор. Во многих организациях используется Samba. Для облегчения жизни вместе с ней поставляется программа SWAT, которая позволяет управлять демонами, принтерами, правами и учетными записями пользователей с помощью веб-интерфейса. Беда в том, что в качестве веб-сервера, отображающего интерфейс управления, используется не Apache, а собственная разработка. С точки зрения экономии ресурсов такое решение вполне оправданно, ведь Apache даже в самом обглоданном состоянии все равно будет содержать в себе больше возможностей, чем нам необходимо для выполнения задачи. На первый взгляд все очень хорошо, но, к сожалению, реализация веб-сервера SWAT не поддерживает никакого шифрования. А это значит, что пароли, имена, явки, адреса конспиративных квартир и прочие секреты передаются по сети с помощью стан-
безопасность дартного HTTP. Переносить интерфейс на Apache лениво, да и трудозатраты себя не оправдают, а взять на себя миссию переписывать SWAT для поддержки SSL рискнет тоже не каждый. Невооруженным глазом видно, что в нашем положении применение stunnel – это как раз то, что доктор прописал. Сразу после инсталляции SWAT вписываем директивы вызова в /etc/services следующим образом: swat
901/tcp# Samba web configuration tool
Ну а в /etc/inetd.conf будет такая строка: swat stream tcp nowait/400 /usr/local/sbin/swat swat
root
↵
Это значит, что SWAT принимает входящие соединения на порт 901. Из этой точки мы можем пойти несколькими путями. Повесить stunnel на порт 902 и соответственно на нем принимать SSL-соединения. Затем расшифровывать данные и отдавать их на порт 901. Тут снова есть варианты – запускать stunnel как отдельный демон или из inetd. Если не стоит задача жесткой экономии ресурсов, то, по моему мнению, наилучшим решением будет запуск stunnel в качестве самостоятельного демона. Так будет проще и надежнее. Ну а в следующих версиях программы возможность запуска stunnel из-под inetd, скорее всего, будет полностью удалена, потому что ей мало кто пользуется. Для приема соединений на порту 901 и передачи расшифрованных данных на порт 901 нужно дописать в конфигурационный файл /usr/local/etc/stunnel/stunnel.conf вот такие строки: [swats] accept = 902 connect = 901
Второй способ состоит в том, чтобы прикрепить swat к порту 901 на локальной петле 127.0.0.1, а stunnel на порт 901 внешних интерфейсов. Примеры методики, которой
нужно придерживаться, приводились в предыдущей статье. Дальнейшая механика полностью повторяет способ номер один. Третий способ выглядит оригинальнее. Вешаем stunnel на порт 901 и при появлении входящих соединений самостоятельно, то есть без помощи inetd, запускаем SWAT. [swats] accept = 901 exec = /usr/local/bin/swat execargs = swat
С воплощением в жизнь этого способа могут возникнуть проблемы. Во-первых, потому что мы работаем от имени пользователя stunnel, а значит, и SWAT будет запущен с такими же правами. Это можно обойти с помощью sudo. А вот вторая неувязка немного сложнее: после запуска сервер stunnel уходит в chroot и значит не сможет работать с файлами, находящимися за пределами /var/tmp/ stunnel/. Это можно будет победить переназначением chroot для stunnel в директорию, где живет Samba. На этом можно завершить рассмотрение приемов обращения с stunnel, который работает в качестве одиночного демона и общается только с SSL-клиентами. Теперь хотелось бы продемонстрировать методику работы для случая, когда ни клиент, ни сервер не умеют работать с SSL. В качестве примера будут выбраны сервер MySQL, работающий под управлением FreeBSD, и стандартный консольный клиент MySQL под управлением Linux. Впрочем, клиент необязательно должен быть консольным, в его качестве может выступать любая программа, умеющая дружить с сервером MySQL через сеть. Схема взаимодействия будет выглядеть примерно так (см. рис. 1). На рабочей станции MySQL-клиент общается с клиентом stunnel, ждушим входящих соединений на порту 127.0.0.1:3307. Stunnel-клиент шифрует полученные данные и отдает их через сеть демону stunnel, работающему на сервере баз данных. Тот, в свою очередь, расшифровывает пакеты и передает их MySQL-серверу. Обратная цепочка работает с точностью до наоборот.
Ðèñóíîê 1
№1, январь 2005
47
безопасность Для простоты восприятия материала вместо создания нового SSL-сертификата будем использовать тот, что создали в первой статье. Сетевой адрес сервера базы данных 10.10.21.29, а рабочая станция соответственно имеет адрес 10.10.21.75. Как я уже говорил, рабочая станция у нас функционирует под ALT Linux. К сожалению, в официальном репозитарии пакетов Sysyphus хранится stunnel весьма просроченной версии. К тому же в личной переписке человек, ответственный за сборку пакета, упомянул, что не планирует обновлять его в ближайшее время. Поэтому придется проводить самостоятельную компиляцию из исходников. Берем пакет с официального сайта http://stunnel.org, распаковываем, настраиваем и собираем. Всем желающим подправить установки по умолчанию предлагается воспользоваться ключами команды configure, благо их достаточно много.
А на сервере соответственно создаем /usr/local/etc/ stunnel/mysql-client.conf и вписываем в него вот это: cert = /usr/local/etc/stunnel/certs/mailserver.cert key = /usr/local/etc/stunnel/certs/mailserver.key chroot = /var/tmp/stunnel pid = /stunnel.pid setuid = stunnel setgid = stunnel debug = 7 output = /var/log/stunnel.log [mysqls] accept = 10.10.21.29:3307 connect = 3306
Запускаем stunnel с обеих сторон: # stunnel /usr/local/etc/stunnel/mysql-client.conf # stunnel /usr/local/etc/stunnel/mysql-server.conf
Не забываем с помощью: # # # # #
tar zxvf stunnel-4.05.tar.gz cd stunnel-4.05 ./configure make all make install
Создаем пользователя, от имени которого будет работать stunnel. # adduser stunnel
И, конечно же, проверяем, что из этого вышло. # id stunnel uid=502(stunnel) gid=503(stunnel) groups=503(stunnel)
Не забываем про создание директорий для временных файлов и сертификатов. Плюс к этому настраиваем права доступа. Не хотелось бы, чтобы к столь важным сведениям имел доступ кто попало. # mkdir /var/tmp/stunnel # mkdir /usr/local/etc/stunnel/certs/
Затем копируем с сервера в папку клиента /usr/local/etc/ stunnel/certs/ сертификат и ключ.
netstat –na | grep LISTEN
проверить состояние интересующих нас портов. И обязательно заглядываем в файлы протоколов /var/log/stunnel.log, дабы убедиться в отсутствии ошибок. На рабочей станции пытаемся соединиться с MySQLсервером. И, скорее всего, получаем ошибку. # mysql -h 127.0.0.1 -P 3307 -u root -p ERROR 1130: Host 'localhost.unreal.net' is not allowed to connect to this MySQL server
Дело в том, что демон stunnel после расшифровки отдает данные серверу MySQL от имени сетевого интерфейса 127.0.0.1. Соответственно, MySQL считает, что мы присоединяемся к нему с localhost. К сожалению, под FreeBSD избавиться от этого никак нельзя. Для Linux выход из ситуации есть, но о нем мы поговорим в следующей статье. Для того чтобы как-то обойти эту неприятность, добавьте пользователя root@localhost.unreal.net в таблицу users и не забудьте обновить текущие привилегии. # mysql
# chown stunnel:stunnel /var/tmp/stunnel ↵ /usr/local/etc/stunnel/certs/ # chmod –R 700 /var/tmp/stunnel ↵ /usr/local/etc/stunnel/certs/
Создаем файл /usr/local/etc/stunnel/mysql-client.conf следующего содержания: cert = /usr/local/etc/stunnel/certs/mailserver.cert key = /usr/local/etc/stunnel/certs/mailserver.key chroot = /var/tmp/stunnel/ pid = /stunnel.pid setuid = stunnel setgid = stunnel debug = 7 output = /var/log/stunnel.log client = yes [mysqls] accept = 127.0.0.1:3307 connect = 10.10.21.29:3307
48
> use mysq; > INSERT INTO user VALUES ('localhost.unreal.net','root','Rw8304MH', 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','' ,'','', 0,0,0); > flush privileges; > quit;
После этого соединение клиента MySQL с сервером должно пройти как по маслу. В принципе работа stunnel под Linux почти ничем не отличается от работы под FreeBSD. Единственная загвоздка будет в том, что вместо inetd придется использовать xinetd. Думаю, что читатель, работающий с Linux, без труда сможет самостоятельно разобраться с этими мелкими несходствами. Казалось бы, мы описали все возможные применения Stunnel, но на самом деле это не так. В следующей статье поговорим о том как с помощью stunnel проводить проверку клиентских сертификатов и о том, какие выгоды это нам сулит.
bugtraq Целочисленное переполнение в Kazaa в протоколе Sig2Dat
Удаленный отказ в обслуживании в OpenBSD
Программа: Kazaa lite k++. Опасность: Высокая. Описание: Обнаружено две уязвимости в менеджере пиринговых сетей Kazaa. Целочисленное переполнение в протоколе Sig2Dat позволяет вызвать отказ в обслуживании или выполнить произвольный код на уязвимой системе. Уязвимость существует в параметре Length в байтах. Удаленный пользователь может передать значение, превышающее 999 999 999 и вызвать переполнение целочисленных. Удачная эксплуатация уязвимости позволит выполнить произвольный код на целевой системе. Пример:
Программа: OpenBSD 3.5, 3.6. Опасность: Высокая. Описание: Уязвимость обнаружена в реализации TCP-стека в OpenBSD. Удаленный атакующий может послать системе пакеты со специально сформированным значением в TCP timestamp option и вызвать панику системы. URL производителя: http://www.openbsd.org. Решение: Установите патчи: ftp://ftp.openbsd.org/pub/ OpenBSD/patches/3.5/common/027_rtt.patch и ftp://ftp.openbsd.org/pub/OpenBSD/patches/3.6/common/010_rtt.patch.
<A HREF="sig2dat://%7CFile:dev-catz5%28.bin%7CLength: 999999999999999999999999999%20Bytes,364489KB%7CUUHash:= DEfm3HmvILkNcbY7j5NGa%2BD11CQ=%7C/">CLICK HERE</A>
Уязвимость в параметре File позволяет выйти за пределы директории и создать файл в любом месте раздела, используя символы перехода между каталогами (‘../’). Примеры: <A HREF="sig2dat://%7CFile:../../../../../../Docume~1/All Users/Start Menu/Programs/Startup/cool.bat%7CLength: 373236528%20Bytes,364489KB%7CUUHash:=DEfm3HmvILkNcbY7j5NGa%2BD11CQ =%7C/">CLICK HERE</A> <script> var i for (i=1;i<10000;i++) { mylocation="<iframe src='sig2dat://% CFile:../../../../../ ../Docume~1/All Users /StartMenu/Programs/Startup/ cool"+i+".bat %7CLength:373236528%20Bytes, 364489KB% 7CUUHash:=DEfm3HmvILkNcbY7j5NGa%2BD11CQ=%7C/'></iframe>"; document.write(mylocation); } </script>
URL производителя: http://www.kazaa.com. Решение: Способов устранения уязвимости не существует в настоящее время.
Переполнение буфера в WebAgent websql CGI-приложении в MySQL MaxDB Программа: MySQL MaxDB WebAgent 7.5.00.18. Опасность: Высокая. Описание: Уязвимость позволяет удаленному пользователю вызвать переполнение буфера и выполнить произвольный код с правами SYSTEM. Уязвимость существует из-за ошибки при проверке данных в websql CGI-приложении. Значение параметра пароля конвертируется в юникод и копируется в стек. Если строка будет длиннее 264 символов, то сохраненные значения для eip и ebp будут перезаписаны. Удачная эксплуатация этой уязвимости позволит атакующему выполнить произвольный код на уязвимой системе с привилегиями SYSTEM. URL производителя: http://www.mysql.com/products/maxdb. Решение: Ограничьте доступ к административным ресурсам системы с помощью межсетевого экрана.
№1, январь 2005
SQL-инъекция в модуле SGallery для PHP-Nuke Программа: SGallery 1.01. Опасность: Высокая. Описание: Уязвимость обнаружена в модуле SGallery для PHP-Nuke. Удаленный пользователь может выполнить произвольные SQL-команды, получить инсталляционный путь к директории и в некоторых случаях выполнить произвольные команды на уязвимой системе. В зависимости от настроек удаленный пользователь может выполнить произвольный php-сценарий на сервере с привилегиями веб-сервера. Сценарий imageview.php некорректно обрабатывает данные в переменных idalbum и idimage. Удаленный атакующий может с помощью специально сформированного URL выполнить произвольные SQL-команды на текущей базе данных. Пример: http://[target]/nuke75/modules/Sgallery/ ↵ imageview.php?idimage=-99/**/UNION/ **/SELECT /**/pwd/**/FROM/**/nuke_authors/**/WHERE/**/ ↵ radminsuper=1
Удаленный пользователь может узнать путь к установочной директории на сервере, если переменные idalbum и idimage не определены. URL производителя: http://www.ser.acmetelecom.ru. Решение: Способов устранения уязвимости не существует в настоящее время.
Выполнение произвольного кода при обработке .psd-файлов в ImageMagick Программа: ImageMagick версии до 6.1.8-8. Опасность: Высокая. Описание: Уязвимость существует в файле coders/psd.c при обработке .psd-файлов. Удаленный пользователь может создать специально сформированный документ в формате Photoshop, который при обработке ImageMagick вызовет переполнение буфера и позволит злоумышленнику выполнить произвольный код на системе. URL производителя: http://www.imagemagick.org. Решение: Установите обновление: http://www.image magick.org/www/download.html.
Составил Александр Антипов
49
безопасность
ВСЕ В ОДНОМ, ИЛИ Hogwash КАК ПРИМЕР Gateway-IDS
СЕРГЕЙ ЯРЕМЧУК В сегодняшнем далеко не благоприятном мире Интернет администраторы должны проявлять особую бдительность при защите вверенных им сетей. В своей работе они используют средства различного характера. Здесь и маршрутизаторы, отправляющие пакеты по целевому назначе-
50
нию и межсетевой экран, отсекающий ненужный трафик. Системы обнаружения атак позволяют выявить вторжение на различных стадиях, сканеры уязвимостей оценивают общую защищенность сети и, наконец, существуют виртуальные частные сети, при помощи которых можно организо-
безопасность вать защищенный канал через Интернет. Каждое из этих средств имеет свои особенности, эффективность и, конечно же, недостатки. Я думаю, нельзя не согласиться с тем, что основой сетевой защиты является в первую очередь брандмауэр, на втором месте по значимости стоит система обнаружения атак. Брандмауэр способен остановить большую часть атак, направленных на компьютеры. Принцип его работы прост и широко известен. Такие устройства, как правило, имеют два сетевых интерфейса, один из которых «смотрит» во внутреннюю сеть, а второй подключен к сети провайдера. Получая пакет с любого из этих интерфейсов, брандмауэр сверяется с правилами, анализирует заголовок пакета и принимает решение о его дальнейшем прохождении или отбрасывании, после чего уменьшает TTL и переправляет пакет по назначению. В сетевых системах обнаружения атак присутствует анализ содержимого пакетов, но они в большинстве случаев не пропускают их сквозь себя, а просто перехватывают то, что проходит по сети. Таким образом, для того чтобы остановить атаку, им приходится либо связаться с брандмауэром, либо включаться в разрыв и самим заниматься отбраковкой пакетов. Первый вариант неудобен тем, что за время реакции системы начальная фаза атаки уже вполне может завершиться и закрытие соединения окажется бессмысленным. При этом время реакции при существенной нагрузке в сети может увеличиваться. Второй вариант также имеет свои недостатки. Главный из них, наверное, это уменьшение общей надежности работы всей сети, обусловленное наличием дополнительного компонента, при выходе из строя которого вся работа останавливается. Не стоит забывать и о необходимости выделения адресов сетевым интерфейсам. В принципе все эти вопросы можно решить, однако, наличие IP-адресов в такой системе позволяет очень легко обнаружить ее при помощи того же traceroute. После этого можно выяснить тип устройства, операционную систему, программное обеспечение, номер версии, чего вполне достаточно для проведения целенаправленной атаки с целью выведения системы, а значит и всей сети, из строя. Что предпринять в такой ситуации? Задачу можно существенно упростить, если опуститься с сетевого уровня вниз на один уровень (т.е. уровень данных) и начать работать непосредственно с кадрами. Внедрение такого устройства не потребует изменения сетевых конфигураций и может быть произведено в любой части сети. Кадры после анализа будут просто передаваться на другой интерфейс. И главное, поскольку устройство не имеет своего IP-адреса, то хотя его работа, в общем, и будет заметна нападающему по косвенным признакам (например, неудаче при проведении атаки) из-за того, что фильтрацию как таковую скрыть просто невозможно, но идентифицировать устройство будет довольно тяжело (оно незаметно для traceroute). Кстати, работа связки «брандмауэр + мост», позволяющей обходиться в такой системе без IP-адресов, была описана еще в конце прошлого века в документе «Linux Bridge+Firewall Mini-HOWTO» (в русском переводе «МиниHOWTO: Совместное использование мостов и Firewall в Linux»). Вручную возиться со всем этим сейчас не придет-
№1, январь 2005
ся, так как данная идея получила дальнейшее развитие в проектах вроде ebtables (http://ebtables.sourceforge.net), которые представляют уже готовое решение, позволяющее без особых проблем собрать подобную систему. На данный момент код ebtables официально включен в ядро 2.6, на указанном выше сайте можно найти патчи к еще популярной в народе версии 2.4. Кроме фильтрации кадров, ebtables позволяет изменять Ethernet MAC-адреса внутри кадров и параметры маршрутизации, также никто не запрещает использовать ebtables совместно с iptables/ip6tables/ arptables, хотя особого смысла в этом лично я не вижу. Как и в iptables, в ebtables имеется возможность контроля за соответствием MAC- и IP-адресов. Правила также имеют схожий синтаксис, поэтому освоить работу с ebtables весьма просто. ebtables -A FORWARD -p IPv4 --ip-src 192.168.1.4 ↵ -s ! 00:11:22:33:44:55 -j DROP iptables -A FORWARD -s 192.168.1.4 -m mac ↵ --mac-source ! :11:22:33:44:55 -j DROP
Конечно, есть и различия, исходящие из особенностей работы этих утилит. Так, кадр Ethernet будет отброшен раньше, чем IP-датаграмма. Кроме того, ebtables берет за основу МАС-адрес, который сравнивается с IP-адресом, а iptables поступает с точностью наоборот. Но не ebtables герой этой статьи. Итак, если возможна фильтрация Ethernet-кадров, то почему бы не использовать и систему обнаружения атак на втором уровне? Преимущества данного подхода очевидны. Кроме невозможности идентификации, такая система сможет не только определять угрозы, но и тут же останавливать их, отбрасывая кадры, изменяя настройки таблиц маршрутизации или фильтров брандмауэра.
Проект Hogwash Такой подход показался настолько логичным и простым решением проблемы, что когда в 1996 году Джейсон Ларсон (Jason Larson) и Джед Хейл (Jed Haile) столкнулись с необходимостью защиты веб-сервера, был сразу же написан начальный вариант системы, позволяющей отфильтровывать опасные пакеты использовавшиеся для вторжения. Первое время проект носил название Scrub и был простым фильтром пакетов, работающим на втором уровне. Постепенно был разработан язык описания атак и движок детектирования, который в 1999 году был заменен кодом Snort (развитие последнего к тому времени шло полным ходом). При этом проект изменил свое название на SnortScrub, которое, впрочем, тоже долго не продержалось, и по маркетинговым соображениям было изменено на Hogwash. В процессе добавления новых функциональных возможностей движок Snort оказался малопригодным для массовой обработки кадров. Поэтому в текущей и пока еще не доведенной до финала версии 0.5 происходит возрождение старого движка «H2». Совместимость со Snort будет сохранена и вынесена в отдельный слой. На данном этапе Hogwash позволяет анализировать информацию и регистрировать большие потоки данных в режиме реального времени. Система, построенная с применением Hogwash, способна реагировать на сканирование, некоторые атаки, направленные на переполнение буфера, определение типа ОС (OS
51
безопасность fingerprinting) и другие. Hogwash относится к классу Gateway Intrusion Detection System и может быть настроен для работы в трех режимах: ! Классическая система обнаружения атак (IDS). ! Встроенная система предотвращения атак (IPS) – Scrubber. ! Контроллер обманных (HoneyPot) систем. В первом случае Hogwash работает подобно любой другой системе обнаружения атак (рис. 1), контролируя проходящий трафик на одном или нескольких интерфейсах и генерируя предупреждения. При этом система способна разрывать подозрительные TCP-соединения и отбрасывать пакеты. Необходимо отметить, что сборка всего потока не производится. Если в принятом пакете имеется частичное совпадение с правилом, то будет принята его следующая часть, и если правило совпадет полностью, то пакеты, принадлежащие данному сеансу, будут отброшены. Для обнаружения сканирования Hogwash отслеживает каждый новый сеанс связи (tcp, udp, icmp) в течение 60 секунд, и если обнаруживается один и тот же источник, то все пакеты, приходящие с него, отбрасываются. Аналогичная реакция имеет место и при обращении с одного источника к 20 уникальным портам и 5 адресам.
Ðèñóíîê 1
При применении в качестве IPS, Hogwash активно просматривает трафик (рис. 2). При этом он способен не только отбрасывать пакеты и изменять параметры маршрутизации, но и переписывать их содержимое (т.н. процедура «промывки» пакетов), убирая опасные данные. Конечно, ничто не мешает использовать его и как обычный пакетный фильтр. В этом режиме поддерживается одновременное наблюдение за 16 интерфейсами. Подключение системы в данном режиме к сети полностью прозрачно, так как она не имеет собственного IP-адреса. Это практически идеальное (и к тому же труднообнаруживаемое) устройство для остановки всех известных атак.
Ðèñóíîê 2
Чтобы не перегружать систему, занимаясь одним и тем же пакетом дважды, в режиме IPS желательно (но в принципе необязательно) отключить переадресацию. echo "0" > /proc/sys/net/ipv4/ip_forward
52
В стартовых скриптах версии 0.4 эта строка уже имеется, версия 0.5 пока не имеет сценариев настройки и запуска, поэтому многое придется проделывать вручную. В экспериментальном на данный момент режиме управления системами HoneyPot (рис. 3), Hogwash не выполняет никаких действий для остановки атаки. Вместо этого он перенаправляет нападающих к одной из обманных (HoneyPot) систем, позволяя таким образом собрать информацию о целях и методах злоумышленников, а также выиграть время, сбить их с толку и лучше подготовиться к обороне.
Ðèñóíîê 3
Установка Hogwash Как уже упоминалось ранее, работа над версией 0.5 еще не полностью закончена, так как в ней произведена первая попытка возрождения движка «H2» вместо Snort. Однако стоит отметить, что она является полностью работоспособной и готовой к применению. Учитывая более адаптированный для работы на втором уровне движок и некоторые изменения в настройках и размещении файлов, я рекомендую остановить свой выбор именно на ней, так как в дальнейшем будет легче осваивать новые версии и обновлять продукт. Также стоит отметить, что в версии 0.4 используется Snort 1.8.6, имеющий проблемы с безопасностью (http://www.iss.net/issEn/ delivery/xforce/alertdetail.jsp?oid=21951), заключающиеся в возможности выполнения произвольного кода, который может быть специально помещен в захваченных сетевых пакетах. С другой стороны, для версии 0.4 можно использовать готовые правила Snort, а для 0.5 пока придется пользоваться имеющимся набором правил и при необходимости составлять их самому. Кроме того, новый движок имеет только 17 параметров для формирования правил, и их явно недостаточно, особенно для работы с UDP-пакетами. Hogwash на сегодняшний день из операционных систем поддерживает только Linux, не требует наличия в ядре стека IP, так что при желании его можно отключить, что только повысит общую защищенность. Также желательно наличие MySQL, куда будут заноситься правила и «отловленные» данные, поскольку при большом их количестве скорость обработки существенно возрастет. Исходный код Hogwash свободно доступен и распространяется по лицензии GPL. Сайт проекта http://hogwash.sourceforge.net. Установка пакета происходит не просто, а очень просто: # tar xzvf devel-0.5-latest.tar.gz # cd devel-0.5
На данный момент сценарий конфигурации не имеет никаких дополнительных параметров настройки. # ./configure
безопасность **************************** Configure script for Hogwash **************************** Checking OS.................LINUX Checking for a C compiler.../usr/bin/gcc Checking endian-ness........LITTLE Checking for MySQL..........Found Checking for daemon.........Found Checking for freopen........Found Checking for dlopen.........Found Done.
# make
Размещение файлов по каталогам производится вручную. Для начала скопируем в положенное место основной исполняемый файл. # cp ./hogwash /usr/sbin/
Для удобства создадим отдельный каталог, в который будут помещены настройки и файлы правил. # mkdir /etc/hogwash # cp -R rules /etc/hogwash/
Для примера возможных настроек пакет содержит два конфигурационных файла stock.config и test.config. # cp ./stock.config /etc/hogwash # mkdir /var/log/hogwash
Теперь можно открыть файл stock.config и познакомиться с настройками. Для удобства работы все настройки разбиты по группам: system, interface, IPList, action, module, routing. Имеется также экспериментальная секция mangling. Раздел «system» содержит общие параметры, которые можно оставить без изменения. <system> Name=Hogwash Sensor ID=1001 Threads=1 # êîëè÷åñòâî ïîòîêîâ, ïðåäíàçíà÷åííûõ äëÿ îáðàáîòêè ïàêåòîâ, # êàê ïðàâèëî, îäèí ïîòîê íà îäèí èíòåðôåéñ (ò.å. Threads=1), # ïðè ðàáîòå íà ìíîãîïðîöåññîðíûõ ñèñòåìàõ èëè â êëàñòåðàõ # çíà÷åíèå ìîæíî óâåëè÷èòü. AlertHeader=%ac %m/%d/%y %h:%min:%s %sip:%sp->%dip:%dp # ýòà íåîáÿçàòåëüíàÿ ñåêöèÿ óêàçûâàåò ôîðìàò çàãîëîâêîâ # ïðåäóïðåæäåíèé, ìîæíî èçìåíèòü íà ëþáîé äðóãîé, # íåîáõîäèìûå äàííûå ïðèâåäåíû â òàáëèöå 1. </system>
Для того чтобы система могла работать, необходимо обязательно указать в секции interface параметры используемых сетевых интерфейсов. Формат следующий: <interface NAME> Type=INTERFACE TYPE # è äâå íåîáÿçàòåëüíûõ îïöèè # ïîêà ïîääåðæèâàåòñÿ òîëüêî ýòîò ïðîòîêîë, ïîýòîìó ìîæíî # åãî îïóñòèòü Proto= Ethernet Role = INTERFACE ROLE </interface>
В поле Type можно выставить следующие значения: linux_raw (Linux), obsd_bpf (OpenBSD), osx_bpf (MacOS X), solaris_dlpi (Solaris, пока еще не полностью работоспособный вариант) и tcpdump. Для type= tcpdump в interface вме-
№1, январь 2005
сто NAME указывается имя файла, куда будут записываться результаты, и значение Threads в большинстве случаев должно равняться 0. Необязательное поле Role содержит подсказку для Hogwash, необходимую при возможном конфликте IP- и МАС-адресов, и может понадобиться для работы с обманными системами. Возможны четыре значения: Internal (внутренний интерфейс), External (внешний интерфейс), Normal (обычный, т.е. без возможного конфликта) и Honey (сюда подключена обманная система и возможна подмена адресов, чтобы нападающий ничего не заподозрил). Пример настройки секции: <interface eth0> Type=linux_raw Proto=Ethernet Role=Normal </interface>
Списки IPLists необходимы для использования в правилах и других частях файла конфигурации. Для удобства можно задать любое число списков. Имя также может быть любым, но чтобы было легче ориентироваться, рекомендуется выбирать осмысленные названия. Возможно использование как отдельного адреса, так и списка адресов, в том числе, и в CIDR-нотации (Classless Internet Domain Routing). 0.0.0.0/0 означает «любой адрес». Пример: <IPList WebServers> 10.34.10.0/16 </list> <IPList DNSServers> 0.0.0.0/0 </list> <IPList FTPServers> 23.3.14.10 10.2.10.3-10.2.10.6 </list> <IPList HonePotServer> 23.3.14.111 </list> <IPList Green> 192.168.100.0/24 </list>
Возможно объединение списков. <IPList AllServers> WebServers DNSServers FTPServers 10.14.10.1 </list>
В секции action создаются наборы реакций на обнаружение тех или иных событий, которые затем будут использованы в правилах. Всего возможно создание 64 наборов реакций. Например: <action default> response=alert console # âûâîä ñîîáùåíèÿ íà êîíñîëü response=alert file(/var/log/hogwash/hogwash.alert) # çàïèñü ïðåäóïðåæäàþùåãî ñîîáùåíèÿ â óêàçàííûé ôàéë response=dump packet(/var/log/hogwash/packet.log) # çàõâàò ïàêåòà, êîòîðûé ñãåíåðèðîâàë ñîîáùåíèå è çàïèñü â ôàéë </action> <action drop>
53
безопасность response=alert console response=alert file(/var/log/hogwash/hogwash.alert) response=dump packet(/var/log/hogwash/packet.log) response=drop # îòáðàñûâàíèå ïàêåòà (èãíîðèðóåòñÿ ïðè ðàáîòå â IDS-ðåæèìå) </action> <action log> response=alert console response=alert file(/var/log/hogwash/hogwash.alert) </action>
Возможны также и другие реакции:
! Запись предупреждения в syslog: response=alert syslog(facility=LOG_AUTH, ↵ priority=LOG_INFO, options=LOG_NDELAY|LOG_PID)
! Посылка предупреждения в сетевой или UNIX-сокет: response=alert socket(www.logger.com:12345)
! Запись предупреждения в базу данных: response=alert mysql(user=hogwash,dbase=hogwash5, ↵ host=localhost,port=3306,pass=password, ↵ logpackets=1)
! Отправка предупреждения по e-mail: response=email(host, from, to, subject)
! Экспериментальная опция, позволяющая отсылать пакеты, удовлетворяющие определенным правилам, на HoneyPot-систему. В качестве параметров указываются временная задержка и адреса, с которых не должно происходить переключение на HoneyPot. При timeout = -1 перенаправление на ложный сервер будет производиться без задержки. response=bns(<timeout>, <GreenList>)
Режим требует наличия трех сетевых карт. <action honeypot> response=alert console response=alert file(/var/log/hogwash/hogwash.alert) response=bns(3600, Green) </action>
Плюс ко всему на данный момент имеется недоработанная, а потому и не описанная в документации опция response=route sip(<interface>, <sip>,<sip>), позволяющая внести изменения в таблицу маршрутизации и отослать исходящие пакеты с определенным IP-адресом в другое место, например, в систему-ловушку. Однако очень трудно представить ситуацию, когда адрес атакующего будет известен заранее. К сожалению, в версии 0.5 исчезла возможность «промывки» пакетов, опции replace в списке действий нет. Объяснений от разработчиков по этому поводу не последовало, возможно, это явление временное и связано с переходом на новый движок, а может быть, разработчики посчитали эту возможность лишней, т.к. для остановки вторжения достаточно отбросить пакет или перенаправить нападающего на обманную систему. Секция module служит для подключения сторонних модулей, которые производят дополнительные проверки, не-
54
зависимо от того, в каком режиме сейчас работает Hogwash (IDS, IPS или управление обманными системами). На момент написания статьи в каталоге modules лежало четыре готовых модуля: ! ATS и ATS2 от All Traffic Summary Logging, предназначены для записи в журнал информации о событиях, происходящих в сети (протоколируется время, IP-адреса и порт источника и получателя, а также некоторая другая информация, позволяющая идентифицировать запросы). 23442543 03/12/2004 19:38:35-19:38:35 192.168.1.1:80<-192.168.1.58:24567 - T 4:4 U 0:0 I 0:0 O 0:0
Модуль ATS2 может быть полезен для сбора статистических данных. ATS является его старой версией, одновременный запуск ATS и ATS2 не допускается. Запись в один журнал ведется на протяжении часа, затем открывается новый файл. <module ATS2> filename=(/var/log/hogwash/TEST_%y_%m_%d_%h.ats) </module>
! Модули WebUnique и DNSUnique позволяют находить ранее неизвестные атаки, направленные на эти сервисы, путем сбора данных и их дальнейшего анализа для внесения изменений в настройки сервисов или код скриптов. Общая идея примерно такова. Большинство «нормальных» посетителей сайта будут постоянно и помногу раз обращаться к одним и тем же страницам, и только злоумышленник с большой вероятностью постарается каждый раз загрузить что-либо уникальное. DNSUnique реализует эту идею в отношении DNS. <module WebUnique> dbase=hogwash5 user=hogwash password=password host=localhost servers=WebServers logfile=WebUnique.log </module> <module DNSUnique> dbase=hogwash5 user=hogwash password=password host=localhost servers= DNSServers logfile= DNSUnique.log </module>
Относительно недавно появился еще один простой модуль covert, демонстрирующий некоторые скрытые механизмы обнаружения. На сегодняшний день он работает только с протоколом ICMP. Наконец, рассмотрим секцию routing, включающую режим маршрутизации пакетов. Если этой секции нет, то Hogwash будет работать в режиме IDS. В самом простом случае, когда требуется маршрутизация, т.е. кадры отправляются только на нужный интерфейс (такая система имеет возможности Flood Protection), секция выглядит так. <routing> MacFilter(eth0, eth1, …) </routing>
Режим моста, когда пакеты после анализа и фильтрации передаются на другой интерфейс, включается опцией
безопасность SBridge(eth0, eth1). Опция Broadcast() включает специфическую обработку широковещательных Еthernet-сообщений (в реальной системе ей трудно найти применение). Опции SIP(INTERFACE IPLIST) и DIP(INTERFACE IPLIST) схожи. Первая пропускает через указанный интерфейс все пакеты, у которых IP-адрес источника указан в списке, вторая пропускает только те, у которых IP-адрес назначения имеется в списке. Использовав в этой секции опцию bns(<InternetIF>, <ProductionIF>, <HoneyIF>, <BlackList>), например, «bns(eth0,eth1,eth2, BlackList)», можно перенаправлять пакеты, подпадающие под действие response=bns, на HoneyPot-систему. В данном случае BlackList содержит список адресов, которые всегда должны перенаправляться в ловушку. Желательно, чтобы HoneyPot имел такие же настройки, что и основная система, но вот IP-адреса у них должны быть обязательно одинаковыми, иначе нападающий заметит подлог и убежит (что тоже в принципе хорошо, хотя и не всегда желательно). Правила обнаружения атак описываются весьма гибко. Например, при обнаружении попытки запуска на одном из вебсерверов команды cmd.exe, правило может выглядеть так. <rule> ip dst(WebServers) tcp dst(80) tcp nocase(cmd.exe) message=%sip:%sip->%dip:%dp cmd.exe attempt action=default </rule>
На момент написания статьи в базу было занесено 7 358 правил, описания которых находились в следующих 7 файлах: general.rules, jason.rules, nikto.rules, nimda.rules, stock.rules, test.rules и x11.rules. Основным является файл stock.rules, остальные при необходимости подключаются в нем инструкциями вроде <include nikto.rules>. При желании правила можно занести в MySQL. Теперь, когда все готово, можно запускать Hogwash. # /usr/sbin/hogwash -c stock.conf -r stock.rules &
Для запуска в качестве демона необходимо добавить опцию –d. Если необходимо только произвести синтаксический анализ составленных правил, используется –t. Для автоматического запуска при старте системы лучше всего написать простенький скрипт. # mcedit /etc/hogwash/hogwash.sh
Тело сценария: #!/bin/bash PATH=/bin:/sbin:/usr/bin:/usr/sbin cd /etc/hogwash killall hogwash echo "0" > /proc/sys/net/ipv4/ip_forward hogwash -c stock.conf -r stock.rules –d
Изменяем права доступа. Или, в случае UNIX-систем: # chmod 700 /etc/hogwash/hogwash.sh <rule> ip dst(WebServers) tcp nocase(/bin/sh) message=attempt to execute /bin/sh action= drop </rule> <rule> icmp type(8) message=%sip-%dip icmp echo request action=log </rule>
В правила может быть включена разнообразная информация, например, IP-адреса, интерфейсы, номера портов, тип протокола верхнего уровня, содержащегося в Еthernetкадре (IP, ARP и т. д) или IP-датаграмме (TCP, UDP, ICMP, IGMP, PIM, OSPF), содержимое пакетов, код и тип ICMP, сюда же заносятся предупреждающие сообщения, выводимые при обнаружении совпадения и требуемая реакция. Сейчас разработчики работают над прямой совместимостью с правилами Snort (данная функция будет частью финальной версии Hogwash 0.5). Òàáëèöà 1.
Âîçìîæíûå äàííûå, âûâîäèìûå â ñîîáùåíèè
И далее любым приемлемым способом прописываем запуск hogwash.sh в стартовых скриптах. Например, для Slackware можно поступить так: # echo /etc/hogwash/hogwash.sh >> /etc/init.d/rc.local
Все, теперь Hogwash будет добросовестно защищать ваши сети. Hogwash является простым в инсталляции и использовании Gateway-IDS. Систему такого типа достаточно тяжело обнаружить: утилиты вроде traceroute не замечают ее и, таким образом, риск проведения DOS сводится к минимуму. Быстрая настройка и небольшое число регулируемых параметров делают Hogwash хорошим средством защиты сетей. Возможность автоматической отсылки пакетов на ложные системы является несомненным достоинством, позволяющим вовремя заметить проблемные участки сети. Вполне возможно, что будущее сетевой безопасности как раз за Hogwash и ему подобными решениями. Как говорится, поживем – увидим.
Ссылки: 1. An introduction to gateway intrusion detection systems – http://www.blackhat.com/presentations/bh-usa-02/bh-us-02haile-hogwash.ppt 2. Securing an Unpatchable Webserver... HogWash! – http:// www.securityfocus.com/infocus/1208
№1, январь 2005
55
программирование
ПУТЕШЕСТВИЕ ИЗ Perl В Excel ИСПОЛЬЗОВАНИЕ Spreadsheet::WriteExcel ДЛЯ ФОРМИРОВАНИЯ ОТЧЕТОВ
СЕРГЕЙ СУПРУНОВ Как было показано в статье «Внутренний веб-сервер» (журнал «Системный администратор», №10(23), октябрь 2004 г.), веб-сервер достаточно удобно использовать для быстрого развертывания несложных приложений, занимающихся сбором, обработкой и выдачей пользователям тех или иных данных. Один из немногих недостатков такого подхода, как было указано, заключается в том, что не всегда удается распечатать качественный отчет, который не стыдно было бы представить начальству или отослать по электронной почте, не вынуждая получателя заниматься копированиемвставкой тела письма и его предпечатной (или в общем плане – предварительной) обработкой. Наиболее универсальным путем решения указанной проблемы является формирование XML-документа, работать с которым умеют многие программы. Однако в данной статье я хочу рассмотреть другой, менее универсальный, но более удобный для конечного пользователя способ – непосредственное формирование файла в формате Excel в CGI-сценарии. Дальнейшее изложение предполагает, что вы знакомы с языком Perl и его применением для CGI-сценариев, умеете настраивать веб-сервер, а также имеете представление о СУБД PostgreSQL (или какой-нибудь другой). Будет рассматриваться работа под FreeBSD, поэтому потребуется также знание базовых принципов UNIX-систем, хотя заставить все описанное работать под Windows, думаю, особого труда не составит. У пользователей Linux никаких проблем возникнуть также не должно. Для решения поставленной задачи будем использовать имеющийся в коллекции CPAN (http://cpan.org) Perl-модуль Spreadsheet::WriteExcel, установить который во FreeBSD можно также и из коллекции портов (/usr/ports/textproc/p5Spreadsheet-WriteExcel), что представляется мне более удобным. На момент написания статьи актуальной была версия 2.11. Данная версия позволяет создавать файлы в формате BIFF8, поддерживающем Unicode. Следовательно, необходимо будет все текстовые строки преобразовывать в UTF8. Подробнее об этом будет сказано далее, при рассмотрении конкретных примеров. К сожалению, от этой версии мне не удалось добиться правильного отображения имени листа, содержащего русские символы. Работа с одной из предыдущих версий 0.43 (несмотря на значительный разрыв
56
номеров версии, от 2.11 ее отделяет не более года), реализующей, по всей видимости, формат BIFF7 и использующей стандартную кодировку Windows, позволяющую сохранять данные в cp1251, никаких проблем ни с кодировкой данных, ни с кодировкой имени листа не выявила. Но поскольку Unicode – это, пожалуй, единственное решение проблем различных кодировок, то на пути к его безраздельному господству придется претерпеть некоторые неудобства. Итак, что позволяет делать модуль WriteExcel? Он предоставляет скрипту на языке Perl ряд функций для записи данных в файл Excel. В качестве примера создадим простейший xls-документ с помощью следующего сценария: Ïðèìåð 1 #!/usr/bin/perl -w # Spreadsheel::WriteExcel tests # Ñòàíäàðòíûé ìîäóëü äëÿ îñóùåñòâëåíèÿ ïåðåêîäèðîâîê use Encoding; # Ìîäóëü äëÿ ðàáîòû ñ ôàéëàìè Excel use Spreadsheet::WriteExcel; # Ïîäàâëåíèå ïðåäóïðåæäåíèé î ìíîãîáàéòíûõ ñèìâîëàõ nowarnings “utf8”; # Ôîðìèðóåòñÿ HTTP-çàãîëîâîê print "Content-Type: text/html\n\n"; print '<H3>Spreadsheet::WriteExcel test</H3>'; # Ñîçäàåòñÿ xls-ôàéë my $workbook = Spreadsheet::WriteExcel-> ↵ new('../public_html/excel/test.xls'); # Ñîçäàåòñÿ «ðàáî÷èé ëèñò» ñ èìåíåì Report my $worksheet = $workbook->add_worksheet('Report'); # Îáúÿâëÿåòñÿ ôîðìàò ÿ÷ååê, èñïîëüçóåìûé â äàëüíåéøåì my $tabformat = $workbook->add_format(); $tabformat->set_border(); # Ïðèìåð âûâîäà äàííûõ áåç ïåðåêîäèðîâêè $worksheet->write(1, 1, 'Ðóññêèé òåêñò ñ ðàìêîé', $tabformat); # Âûâîä ASCII-òåêñòà $worksheet->write(‘B3’, 'English text.'); # Âûâîä äàííûõ ñ ïåðåêîäèðîâêîé $worksheet->write(3, 1, decode(‘koi8-r’, ↵ ' Ðóññêèé òåêñò ñ ðàìêîé '), $tabformat); # Ññûëêà íà ñôîðìèðîâàííûé ôàéë print "<A href='/excel/test.xls'>Ðåçóëüòàò</A>";
программирование Обратите внимание на строку Spreadsheet::WriteExcel-> new(..), которая создает объект (соответствующий тому, что в терминах Excel именуется «книгой»), с которым в дальнейшем будет вестись вся работа. В качестве параметра конструктору new() передается имя создаваемого файла (если файл расположен вне текущего каталога, требуется указать полное имя, включающее абсолютный или относительный путь к файлу). Данный файл должен существовать и быть доступным для записи сценарием либо сценарий должен иметь права на создание файла в указанном каталоге. Поскольку предоставлять сценариям право писать в один из каталогов дерева веб-сервера – не самая лучшая идея (так как в случае взлома сервера у злоумышленника будет больше шансов «нагадить»), то имеет смысл для этих целей создать специальную папку (например, /var/tmp/excel) или использовать /var/tmp. Хотя, с другой стороны, в этом случае мы не сможем создать ссылку на сформированный файл для непосредственного скачивания, и придется использовать сценарий, который будет отдавать файлы пользователю через http, например, такой: Ïðèìåð 2. Ñöåíàðèé getexcel.cgi #!/usr/local/bin/perl -w # getexcel.cgi use CGI; $root = '/var/tmp/excel'; # Ïîëó÷àåì èìÿ ôàéëà èç HTTP-çàïðîñà $cgi = CGI->new(); $file = $cgi->param('file'); # Âûðåçàåì íåáåçîïàñíûå ñèìâîëû – èìÿ ôàéëà ìîæåò ñîäåðæàòü # òîëüêî öèôðû è áóêâû â íèæíåì ðåãèñòðå. # Ðàñøèðåíèå íå óêàçûâàåòñÿ $file =~ s/[^a-z0-9]//g; $file = "$root/$file.xls"; # Îòêðûâàåì ôàéë íà ÷òåíèå, óñòàíàâëèâàåì äâîè÷íûé ðåæèì open(F, "$file") || &nosuchfile; binmode(F); # Ôîðìèðóåì íóæíûé çàãîëîâîê print "Content-Disposition: form/data; name=\"$file\"; ↵ filename=\"$file\"\n"; print "Content-Type: application/vnd.ms-excel; ↵ name=\"file.xls\"\n"; print "Content-Transfer-Encoding: binary\n\n"; # Âûâîäèì ñîäåðæèìîå ôàéëà while(<F>) { print; } close(F); #----------------------------------- subs sub nosuchfile { print "Content-Type: text/html\n\n"; print "<H3>Ôàéë '$file' íå íàéäåí.</H3>"; return(-1); }
Как компромисс можно заранее создать в одном из каталогов, доступных веб-серверу, нужные файлы и дать на них требуемые права записи, запретив, однако, запись в каталог. При этом можно даже разместить на них статические ссылки, которые всегда будут возвращать последний созданный отчет. Этот вариант выглядит более безопасным, по крайней мере для сервера, однако остается гипотетическая вероятность заполнения злоумышленником
№1, январь 2005
всего свободного пространства в текущем разделе (хотя если уж взлом состоялся, то наверняка «хакер» найдет себе более интересные занятия). К тому же, если кому-то удастся записать в такой файл, скажем, вирус, то можно навсегда потерять доверие ваших пользователей. Впрочем, указанные проблемы становятся актуальными лишь в случае, если злоумышленнику удастся проникнуть в систему с правами, достаточными для записи в эти файлы, но вопросы обеспечения безопасности сервера выходят за рамки данной статьи. Еще один путь решения проблемы временных файлов – выдача данных, формируемых модулем Spreadsheet::WriteExcel, непосредственно в стандартный поток вывода вместо сохранения на диск. Начало примера 1 в этом случае будет выглядеть так: #!/usr/bin/perl -w # Spreadsheel::WriteExcel tests use Encode; use Spreadsheet::WriteExcel; nowarnings “utf8”; print "Content-Type: application/vnd.ms-excel\n\n"; my $workbook = Spreadsheet::WriteExcel->new('-'); . . .
В случае если скрипт, создающий файл, работает как CGI-сценарий и должен возвращать данные с использованием протокола HTTP, перед началом формирования выходного потока нужно будет передать браузеру заголовок с указанием mime-типа application/vnd.ms-excel, который позволит идентифицировать передаваемые данные именно как файл в формате Excel. Здесь используется минимальный заголовок, более подробный приведен выше, в getexcel.cgi. Это тоже хороший способ, но из недостатков следует указать на невозможность повторного использования уже сформированного файла. Необходимость в этом возникает нечасто, но все же возникает (например, если данные меняются реже, чем их запрашивают пользователи, то между изменениями данных разумно было бы отдавать пользователю уже сформированный отчет, а не создавать его заново). Обратите внимание, что в этом случае команды print (и прочие, осуществляющие вывод в стандартный поток) могут использоваться только для формирования HTTP-заголовка. Весь остальной вывод (вывод данных) должен осуществляться исключительно силами пакета Spreadsheet::WriteExcel. Вернемся к нашему примеру 1. Объект, соответствующий файлу, у нас уже создан, теперь нужно создать лист (для этого используется метод add_worksheet) и можно приступать к записи данных. Для записи используется метод листа write, формат которого может быть одним из следующих: $worksheet->write(cell, text[, format]) $worksheet->write(rownum, colnum, text[, format])
То есть адрес ячейки можно задавать как в формате «A1», так и номерами строки и столбца. Ячейке A1 соответствуют строка 0 и столбец 0. Необязательный параметр format передает объект, создаваемый методом «книги» $workbook->add_format(). Он
57
программирование позволяет изменять принятое по умолчанию форматирование ячейки, для чего используются соответствующие методы данного объекта. В примере выше мы задаем видимую границу вокруг соответствующих ячеек с помощью метода set_border(). Поскольку версия 2.11 модуля WriteExcel подразумевает запись данных в формате Unicode, то все текстовые строки требуется преобразовать в формат UTF8. (Чтобы посмотреть на результат вывода текста без перекодировки, в пример 1 добавлена строка, выводящая в одну из ячеек русский текст непосредственно). Для этого я использую стандартный модуль Encode, функция которого decode(charset, string) осуществляет преобразование строки string, хранящейся с использованием кодировки charset, во «внутреннее представление Perl» (как сказано в man Encode). В моем случае «внутренне представление» совпадает с UTF8, поэтому дальнейших преобразований не требуется. Но тот же man Encode предупреждает, что может быть и по-другому, поэтому в общем случае может потребоваться использовать также функцию encode() для получения нужной кодировки. Ну и чтобы подавить вывод предупреждений «Wide character in print at…», которые формируются при попытке вывода оператором print многобайтных символов, используется прагма «no warnings “utf8”». Еще одно замечание о Spreadsheet::WriteExcel – поскольку в самом модуле используется прагма Perl use strict, то даже если вы предпочитаете более вольный стиль, переменные, используемые им ($workbook, $worksheet, $tabformat) должны быть объявлены до использования, например, как my. В противном случае модуль выдаст сообщение «Can’t use an undefined value…» (невозможно использовать неопределенное значение), и xls-файл сформирован не будет (точнее, сам файл создастся, но будет пустым). Хотя аварийного завершения работы сценария в этом случае не происходит. Для общего представления о модуле Spreadsheet::WriteExcel изложенного, думаю, достаточно. Перейдем к более содержательному примеру. Пусть у нас в базе данных есть таблица с тарифами на услуги доступа в Интернет по технологии ADSL, и требуется предоставить абонентам возможность как ознакомиться с ними на html-странице, так и загрузить файл в формате Excel, содержащий эту информацию. Конечно, тарифы меняются не так часто, и, вероятно, проще было бы решить поставленную задачу разработкой статической страницы и заранее созданным файлом Excel. Тем не менее, этот пример хорош как раз своей простотой. Итак, в какой среде нам предстоит работать. База данных PostgreSQL, веб-сервер Apache с поддержкой CGI, Perl с установленным модулем Spreadsheet::WriteExcel. Все это работает под FreeBSD 5.3. Таблица тарифов создана такой командой:
Для примера заполним таблицу несколькими записями: test=> select * from trf_adsl; trfname | payment | traflimit | overlimit | comment --------------------------------+------------+-----------+------------+--------------------------------------"Свободный" | 0.00 | 0 | 2.30 | Мин. предоплата – 300 руб. "Сотка" | 200.00 | 100 | 2.15 | "Школьный" | 250.00 | 120 | 2.05 | "Студенческий" | 300.00 | 150 | 2.00 | До 1.06.2005 "Корпоративный" | 1200.00 | 750 | 1.55 | (записей: 5)
Для простого вывода этих данных на html-страницу все достаточно банально: Ïðèìåð 3. Ñöåíàðèé showtrf.cgi #!/usr/local/bin/perl -w # showtrf.cgi use DBI; $dbh = DBI->connect('dbi:Pg:dbname=test', 'serg', ''); $hres = $dbh->selectall_hashref('SELECT * ↵ FROM trf_adsl', 'traflimit'); print <<__ENDHTML__; Content-Type: text/html <LINK rel='stylesheet' type='text/css' href='/_serv_/main.css'> <H2>Òàðèôû íà óñëóãè äîñòóïà â Èíòåðíåò ïî ADSL</H2> <TABLE border='1'><TR> <TH>Òàðèôíûé ïëàí <TH>Àáîíåíòñêàÿ ïëàòà <TH>Âêëþ÷åííûé òðàôèê <TH>Ñòîèìîñòü<BR>ñâåðõëèìèòíîãî<BR>òðàôèêà <TH>Ïðèìå÷àíèå </TR><TR> __ENDHTML__ @sorted = keys %$hres; @sorted = sort(@sorted); foreach $payment (@sorted) { print "\t<TD>${$$hres{$payment}}{'trfname'}\n"; print "\t<TD id='nr'>${$$hres{$payment}}{'payment'}\n"; print "\t<TD id='nr'>${$$hres{$payment}}{'traflimit'}\n"; print "\t<TD id='nr'>${$$hres{$payment}}{'overlimit'}\n"; print "\t<TD>${$$hres{$payment}}{'comment'}\n"; print "</TR><TR>\n"; } print "</TR></TABLE>\n";
Результат тоже вполне обычен (рис. 1, внешний вид определяется подгружаемой таблицей стилей /__serv__/ main.css).
test=> create table trf_adsl (trfname varchar, test(> payment numeric(7,2), test(> traflimit numeric(5), test(> overlimit numeric(5,2), test(> comment varchar); CREATETABLE
Назначения полей следующие:
58
Ðèñóíîê 1
программирование if(length($tmp) > $rowidth[2]) ↵ { $rowidth[2] = length($tmp); } $ws->write($row, 2, koi2utf($tmp), $tabfmt);
Создать в формате Excel не намного сложнее. ПриÏðèìåð 4.файл Ñöåíàðèé exceltrf.cgi веду#!/usr/local/bin/perl код сценария полностью, а ниже дам ряд пояснений: -w # exceltrf.cgi
$tmp = ${$$hres{$payment}}{'overlimit'}; if(length($tmp) > $rowidth[3]) ↵ { $rowidth[3] = length($tmp); } $ws->write($row, 3, koi2utf($tmp), $tabfmt);
# Ïîäêëþ÷åíèå íóæíûõ ìîäóëåé useDBI; use Encode; use Spreadsheet::WriteExcel; nowarnings “utf8”;
$tmp = ${$$hres{$payment}}{'comment'}; if(length($tmp) > $rowidth[4]) ↵ { $rowidth[4] = length($tmp); } $ws->write($row, 4, koi2utf($tmp), $tabfmt);
# Ôóíêöèÿ ïåðåêîäèðîâêè èç koi8-r â utf8 sub koi2utf { $text = shift; return decode(‘koi8-r’, $text); }
}
# Çàïðîñ ê áàçå äàííûõ $dbh = DBI->connect('dbi:Pg:dbname=test', 'serg', ''); $hres = $dbh->selectall_hashref('SELECT * ↵ FROM trf_adsl', 'traflimit');
# Óñòàíàâëèâàåì óòî÷íåííóþ øèðèíó ñòîëáöîâ for($i = 0; $i < 5; $i++) { $ws->set_column($i, $i, $rowidth[$i] + 3); }
# Ñîçäàåì «êíèãó» è ëèñò ñ èìåíåì «ADSL» $fn = 'tr' . time() . '.xls'; my $wb = Spreadsheet::WriteExcel-> ↵ new('../public_html/excel/' . $fn); my $ws = $wb->add_worksheet(‘ADSL');
# Âûâîäèì ññûëêó, ïî êîòîðîé ìîæíî äîáðàòüñÿ # äî ñôîðìèðîâàííîãî ôàéëà print <<__ENDHTML__; Content-Type: text/html
# Çàäàåì àëüáîìíîå ðàñïîëîæåíèå ëèñòà $ws->set_landscape(); # Ôîðìàò òåêñòà, èñïîëüçóåìûé äëÿ ôîðìèðîâàíèÿ çàãîëîâêà my $textfmt = $wb->add_format(font => 'Arial', size => 18, color => 'blue', italic => 1); $textfmt->set_merge(); # Ôîðìàò «øàïêè» òàáëèöû my $headfmt = $wb->add_format(); $headfmt->set_bold(); $headfmt->set_align('center'); $headfmt->set_align('vcenter'); $headfmt->set_text_wrap(); $headfmt->set_border(); $headfmt->set_bottom(6); my $mygray = $wb->set_custom_color(40, '#AAAAAA'); $headfmt->set_bg_color($mygray); # Ôîðìàò îñòàëüíûõ ÿ÷ååê òàáëèöû my $tabfmt = $wb->add_format(num_format => '0.00', ↵ border => 1); # Îáúåäèíåíèå ÿ÷ååê A1-E1 $ws->merge_range('A1:E1', koi2utf('Òàðèôû íà óñëóãè äîñòóïà â Èíòåðíåò ïî ADSL'), $textfmt); # Âûâîä «øàïêè» òàáëèöû $ws->write('A3', koi2utf('Òàðèôíûé ïëàí'), $headfmt); $ws->write('B3', koi2utf('Àáîíåíòñêàÿ ïëàòà'), $headfmt); $ws->write('C3', koi2utf('Âêëþ÷åííûé òðàôèê'), $headfmt); $ws->write('D3', koi2utf('Ñòîèìîñòü ñâåðõëèìèòíîãî ↵ òðàôèêà'), $headfmt); $ws->write('E3', koi2utf('Ïðèìå÷àíèå'), $headfmt); # Íà÷àëüíûå çíà÷åíèÿ øèðèíû ñòîëáöîâ @rowidth = (15, 10, 10, 15, 15); # Îñíîâíóþ òàáëèöó âûâîäèì, íà÷èíàÿ ñ 4-é ñòðîêè $row = 3; # Ïîñòðî÷íûé âûâîä òàáëèöû @sorted = keys %$hres; @sorted = sort(@sorted); foreach $payment (@sorted) { $tmp = ${$$hres{$payment}}{'trfname'}; if(length($tmp) > $rowidth[0]) ↵ { $rowidth[0] = length($tmp); } $ws->write($row, 0, koi2utf($tmp), $tabfmt); $tmp = ${$$hres{$payment}}{'payment'}; if(length($tmp) > $rowidth[1]) ↵ ⎯ { $rowidth[1] = length($tmp); } $ws->write($row, 1, koi2utf($tmp), $tabfmt); $tmp = ${$$hres{$payment}}{'traflimit'};
№1, январь 2005
$row++;
<A href="/excel/$fn">$fn</A> __ENDHTML__
Для тестирования я выбрал сохранение формируемого файла в папке /excel дерева каталогов веб-сервера (см. путь в тексте примера), для которой установлены соответствующие права, позволяющие сценарию создавать в нем файлы. Почему на реальных системах так делать не следует, мы уже обсуждали. Имя файла формируется динамически с использованием значения текущего времени (см. переменную $fn). Сделано это для того, чтобы на стадии тестирования не тратить время на борьбу с ретивыми браузерами и прокси-серверами, норовящими сэкономить вам трафик за счет кэширования, а также чтобы сохранить историю экспериментов. После создания рабочего листа $ws с помощью метода книги add_format() описываются несколько объектов, которые будут отвечать за форматирование ячеек. Свойства ячеек можно задавать как непосредственно в параметрах add_format (см. $textfmt и $tabfmt), так и с помощью методов объекта формата после его создания (см. $headfmt). Заголовок и «шапка» таблицы формируются «вручную» с явным указанием ячеек, куда текст помещается. Метод merge_range() действует аналогично write(), но позволяет объединить несколько ячеек. Далее в цикле выполняется выборка из хэша результатов запроса к БД, и соответствующие ячейки заполняются данными из таблицы trf_adsl. Здесь для метода write() удобнее использовать «раздельную адресацию», когда ячейка определяется номерами строки и столбца. Переменная $tmp и вычисления длины нужны для того, чтобы установить ширину столбцов, позволяющую целиком видеть содержимое ячеек. Вообще проблема вычисления ширины столбца достаточно сложна, чтобы подходить к ней «академически». Я предпочитаю некоторое сочетание методов «на глазок» и «подогнать». Результат получается вполне приемлемым при минимуме затрат сил и времени. А именно, первоначальную ширину столбцов я определяю подбором по ширине заголовков (результат занесен в массив @rowidth). В дальнейшем пользуюсь тем, что в Excel ширина столбца задается в символах стандартного шриф-
59
программирование та. Поскольку шрифт для основного текста я не меняю, то просто выполняется поиск наибольшей длины строки, которая будет заноситься в столбец, и если она превышает первоначальные значения в @rowidth, – производится корректировка. Ну и при установке ширины столбцов (цикл for в конце сценария) еще добавляю 3 символа «про запас». Результат представлен на рис. 2. Теперь осталось собрать все воедино. Итоговый файл я приводить не буду – он просто объединяет предыдущие два (showtrf.cgi и exceltrf.cgi) таким образом, чтобы при обращении к странице тарифы выводились на экран, и одновременно формировался бы файл, ссылка на который будет появляться на этой же странице. Файл с требуемым именем в итоговом варианте лучше создать заранее (можно даже пустой, например, командой touch), а с каталога, в котором он размещен, снять права на запись. Впрочем, различные способы решения проблемы «временных файлов» были указаны выше, и окончательный выбирать все же вам.
Ðèñóíîê 2
Вот, пожалуй, и все, что я хотел сказать в этой статье. Можно было бы подробней пройтись по методам записи в ячейки, форматированию, способам указания формата листа и т. д. Однако все это очень детально и понятно описано в справочном руководстве man Spreadsheet::WriteExcel (эту же справку можно получить и через perldoc – кому как удобнее), к тому же с массой наглядных примеров, так что я уже не смогу написать лучше. Скажу лишь, что модуль содержит ряд специализированных методов вывода помимо универсального write (например, write_number, write_string, write_formula и т. д.), которые могут быть использованы для конкретизации типа заносимых в ячейку данных. Существует возможность гибко управлять параметрами страницы (формат бумаги, ориентация листа, поля, масштаб и т. д.). Список методов изменения формата ячеек также намного богаче, чем было показано в статье. В общем, можно сказать, что Spreadsheet::WriteExcel позволяет делать практически все, что вы можете сделать в Excel вручную (за исключением разве что макросов). В заключение замечу, что описанный модуль в паре со Spreadsheet::ParseExcel (который позволяет извлекать данные из xls-файлов) можно использовать и для непосредственной обработки файлов Excel, например, чтобы сформировать какой-нибудь годовой отчет на основе ежемесячных. Возможно, это выглядит несколько громоздко, но все же позволяет сократить объем рутины, которую так или иначе приходится делать.
ИТОГИ КОНКУРСА В августовском номере журнала за прошлый год редакцией был объявлен конкурс на лучшие статьи, описывающие успешный опыт в области системного администрирования. В течение нескольких месяцев в редакцию приходили материалы и предлагались интересные темы. В итоге несколько конкурсных статей опубликованы в октябрьском и ноябрьском номерах журнала – это материалы Романа Гребенникова, Сергея Супрунова, Ивана Коробко и Дениса Батранкова. Всем авторам опубликованных материалов перечислен гонорар за статьи. безопасность
конкурсная статья
ПОИСК ТРОЯНОВ ВРУЧНУЮ
ДЕНИС БАТРАНКОВ В этой статье вы найдете ответы на следующие вопросы:
Что делать, если вы предполагаете, что на вашем компьютере с Windows установлена программа-шпион или троян?
Как найти троянскую программу или spyware, если ваш антивирус или AdWare ее не находит?
Статья для начинающих системных администраторов и опытных пользователей Windows описывает возможные способы поиска троянских программ и также описывает, как использовать для этого поиска программы и утилиты из стандартной поставки Windows 2000, XP и 2003 и программы сторонних разработчиков: netstat, msconfig, msinfo32, tlist, Sysinternals TCPView, CurrPorts, WinTasks, Security Task Manager, Starter, Winpatrol, Sysinternals Autoruns, Sysinternals ProcessExplorer, MoveOnBoot, Microsoft PortReporter, System Safety Monitor. Если коротко описать процесс поиска программы, выполняющей нежелательные действия, то алгоритм обычно такой: Обновить базу данных установленного на вашем компьютере антивируса и проверить им все локальные диски. (Если антивируса нет, то установить его.) Вам нужно осознавать, что если антивирус не обнаружил троянов, то это не значит, что их у вас нет. На компьютере может работать свежий троян или специально подготовленная для вас программа-шпион, которой еще нет в базах ни одной компании производителя антивируса. И, возможно, вы тот человек, который первым выявит и пошлет эту программу для исследования в антивирусную компанию. Посмотреть, какие процессы работают на компьютере и какие соединения с Интернетом ими используются. Возможно, на диске появились новые файлы, возможно, старые файлы изменились. Возможно, в реестре появились новые ключи или параметры.
Просмотреть логи персонального firewall. Если firewall не смог заблокировать несанкционированные соединения трояна в силу своей недостаточной функциональности или неправильной настройки, то есть надежда, что он хотя бы запротоколировал, какие соединения были пропущены в Интернет. Если хорошего персонального firewall нет, то хотя бы включите встроенный в Windows XP firewall, который называется ICF (как это сделать, описано на http://www.microsoft.com/rus/windowsxp/ using/howto/networking/icf.asp). Протоколы встроенного firewall можно посмотреть с помощью любого текстового редактора, открыв файл C:\WINDOWS\ pfirewall.log. Но лучше использовать более удобные утилиты, ссылки на которые легко найти при помощи Google (например, набрав в строке поиска «XP firewall logger»). Первый пункт достаточно понятен и помогает в 80% случаев. За третий пункт нужно браться в самом запущенном случае и еще лучше со специалистом по компьютерной безопасности (далее КБ). Давайте попробуем выполнить действия, описанные во втором пункте. Тем более что при внимательном выполнении всех операций можно найти и убить любую гадость, засевшую в вашем компьютере. Возникает вопрос, нужно ли отключаться от Интернета, если мы ищем вирус или троян? Вам понадобятся различные утилиты для поиска трояна (какие конкретно будет описано далее). Если эти утилиты уже есть или на жестком диске, или на компакт-диске, или у вас есть возможность сходить за нужными дисками, или скачать и записать на компакт-диск нужные программы на другом незараженном компьютере, то необходимо отключиться от Сети. Это нужно сделать, чтобы предотвратить дальнейшую утечку информации с компьютера. Отключаться нужно даже от локальной сети, например, сети офиса или домашней сети, чтобы не заражать соседние компьютеры. Однако иногда встречаются особо запущенные случаи,
безопасность в которых приходится скачивать нужные программы через Интернет. Например, я однажды приехал в гости к родственникам в Сибирь, обрадовался наличию компьютера с модемным доступом к Интернету, сел за него и, нажав по привычке <Ctrl-Alt-Del>, сразу обнаружил трояна в списке процессов. Поскольку нужных программ под рукой не было, пришлось лечить вручную. Единственной «защитой» этого компьютера с Windows XP был гордо стоящий антивирус с базами вирусов двухгодичной давности. В Windows даже не был включен ICF. К сожалению, подавляющее большинство пользователей неопытны и несведущи в вопросах компьютерной безопасности. Компьютеры на платформе Intel и операционная система Windows являются высокотехнологичными продуктами. Ведь даже среди тех, кто пользуется общеизвестной программой Microsoft Word, не так много людей, кто изучал его на курсах или хотя бы читал к нему документацию. Что тут говорить про образованность в области компьютерной безопасности. К каждому пользователю специалиста по компьютерной безопасности не приставишь. Поэтому на таких компьютерах все подготовительные мероприятия их владельцы будут делать сами при работающем трояне и подключенном Интернете, поскольку Интернет – единственное место, где они могут найти помощь и программное обеспечение для поиска троянов. Тем более чего им бояться – все важное троян уже наверняка украл и отослал своему владельцу. Но даже в этом случае, после того как вы скачали все необходимые утилиты на локальный диск, нужно отключиться от Сети. Итак, боевая задача состоит в том, чтобы успешно пройти три этапа: найти трояна, убить его и поменять свои украденные пароли. Именно в такой последовательности. Замечание: программа в операционной системе Windows представлена в виде процесса, в котором может работать несколько нитей, и все эти нити загружены в память из файлов, хранящихся на диске. Как правило, это файлы с расширением EXE и DLL. Расширения могут быть и другими. Злоумышленники часто используют другие расширения, чтобы никто не догадался. Некоторыми проявлениями троянских программ являются: несанкционированные соединения c различными хостами в Интернете; открытые программами соединения, ожидающие подключения извне; попытка открыть ненужные для нормальной деятельности файлы на локальном диске; добавление себя в списки автозапуска; маскировка под стандартные системные процессы и размещение в системной папке Windows.
Находим троянскую программу, которая ждет входящего соединения Обычно авторы таких программ называют свои программы «программами удаленного управления». Типичной иллюстрацией этого вида троянских программ является Back Orifice (см. описание http://www.viruslist.com/viruslist.html?id= 3957&gloss=8227). Такие программы позволяют делать на
вашем компьютере все что угодно: скачивать файлы, рассылать спам, быть прокси-сервером, участвовать в DOSатаке, быть плацдармом для других атак, естественно, в рамках функций, предоставляемых им имеющейся операционной системой. В данном случае мы рассматриваем версии Windows: 2000 SP4, XP SP1, 2003. Такие программы открывают TCP-порт на компьютере жертвы, устанавливают его в состояние LISTENING и ждут, когда хакер подключится на этот порт. Таким образом, нам нужно выявить все процессы, которые открыли TCP-порты и которые находятся в состоянии LISTENING, и решить, одобряете ли вы это соединение или нет. То же самое можно сказать про UDP-порты – за ними тоже надо смотреть, с единственным отличием, что у них нет состояний – с этих портов может как приниматься информация, так и отсылаться. С ходу можно сказать, что если у вас обычный компьютер, подключенный к выделенной линии или через модем в Интернет, то в идеале у вас не дожно быть слушающих портов. Даже если приложения или сервисы Windows открыли эти порты, то они должны быть закрыты персональным firewall. Чтобы выявить программы, которые ожидают (и устанавливают) соединения в Windows XP и Windows 2003, можно, конечно, воспользоваться стандартной утилитой netstat c параметрами -ano. (Параметр -а заставляет netstat показывать все имеющиеся подключения и ожидающие порты, -n преобразует вывод адресов и портов в числовой формат, -o отображает для каждого подключения идентификатор процесса, создавшего это подключение). В Windows 2000 ключ -o еще не был изобретен. Например:
Победителем признан Денис Батранков, приславший статью «Поиск троянов вручную» (№10, октябрь 2004 г.) Автору вручается подписка на журнал «Системный администратор» на 2005 год, а также подшивка прошлых номеров журнала. №9(22) сентябрь 2004 подписной индекс 81655 www.samag.ru
№10(23) октябрь 2004 C:\Documents and Settings\User>netstat -ano
подписной индекс 81655 www.samag.ru
Активные подключения Имя TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP TCP
Локальный адрес 0.0.0.0:135 0.0.0.0:445 0.0.0.0:1025 0.0.0.0:4928 0.0.0.0:4929 0.0.0.0:4946 0.0.0.0:6213 0.0.0.0:6218 0.0.0.0:6247 0.0.0.0:6253 0.0.0.0:6299 0.0.0.0:6344 0.0.0.0:9762 0.0.0.0:10641 0.0.0.0:10676 0.0.0.0:10892 127.0.0.1:111 127.0.0.1:143 127.0.0.1:3044 127.0.0.1:3045 127.0.0.1:3046 127.0.0.1:3085 127.0.0.1:5335 127.0.0.1:8888
Внешний адрес 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0 0.0.0.0:0
Состояние LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING
PID 856 4 1028 3660 3660 3660 3660 3660 3660 3660 3660 3660 2324 2884 2324 2324 2676 2676 1608 1028 1028 2324 3232 3232
Результат, как видите, аскетичен: порты, конечно, выводятся, но вместо информации о приложениях выдается только номер процесса. Хотелось бы еще узнать имя процесса и местоположение файла, из которого он был запущен. Но давайте хотя бы разберемся с тем, что уже есть. Если вы увидели у себя много TCP-соединений в состоянии LISTENING, то не пугайтесь – это, скорее всего, не трояны, а работающие по умолчанию стандартные сервисы Windows.
Linux на страже Windows: обзор системы резервного копирования BackupPC GRSecurity – система безопасности для Linux
Знакомство с Cooperative Linux Роутер без диска №11(24) ноябрь 2004 подписной индекс 81655 www.samag.ru
Утилита nLite: формируем свой дистрибутив Windows XP/2000/2003
Идеальный карманный компьютер для системного администратора
Windows XP Service Pack 2 глазами системного администратора
Bluetooth + Linux Возможно ли повышение точности IDS Настройка squid для использования авторизации из домена Windows 2000
PostgreSQL: графический клиент pgAdmin
Установка и настройка W2K Server
FreeBSD tips: устанавливаем VPN Восстановление данных на NTFS-разделах
Пакетный фильтр OpenBSD
Четырехузловой кластер с балансировкой нагрузки без внешнего массива данных
Танцуем самбу
PostgreSQL: функции и триггеры
Linare – настольный дистрибутив Linux
Внутренний веб-сервер
Использование аппаратных ключей в целях аутентификации в Linux
Иммунная система для компьютера
STAT – совсем другая IDS
Система обнаружения атак SHADOW
Пассивный перехват трафика
Поиск троянов вручную
Биллинг для АТС на базе PostgreSQL
Запись дисков CD-R/RW в Linux
Обработка переадресованных http-запросов
Создание и настройка сервера терминалов
№12(25) декабрь 2004 подписной индекс 81655 www.samag.ru
Единая учетная запись для Windows и UNIX в Active Directory Копирование файлов в автоматическом режиме с множества компьютеров через SSH Защита сетевых сервисов с помощью stunnel
Мониторинг UNIX-серверов c помощью Nagios и SNMP Использование бездисковых Linux-станций с загрузкой по сети
Пакетные команды интерфейса ATAPI PHP 5 – пришествие неизбежно
Автоматизация FTP с помощью Python
68
№10(23), октябрь 2004
69
Уважаемые читатели! Конкурс продолжается – присылайте свои материалы, самые интересные будут опубликованы на страницах журнала. Итоги следующего этапа конкурса будут подведены в июльском номере журнала. Успехов! Условия участия и подробности смотрите на сайте журнала www.samag.ru в разделе «Конкурс».
60
bugtraq Выполнение произвольного кода и отказ в обслуживании в Midnight Commander Программа: Midnight Commander до 4.5.55 версии. Опасность: Высокая. Описание: Несколько уязвимостей в Midnight Commander позволяют удаленному пользователю вызвать отказ в обслуживании и выполнить произвольный код на уязвимой системе. Множественные уязвимости форматной строки в файлах src/utilunix.c и vfs/fish.c позволяют удаленному пользователю вызвать отказ в обслуживании или выполнить произвольный код на уязвимой системе с привилегиями пользователя, запустившего mc. Множественные переполнения буфера в файлах src/ key.c, vfs/sfs.c, vfs/direntry.c, gtkedit/syntax.c, src/wtools.c, src/ utilunix.c, src/boxes.c, src/charsets.c и vfs/cpio.c дают возможность злоумышленнику вызвать отказ в обслуживании и выполнить произвольный код. Уязвимости в файле gtkedit/syntax.c позволяют удаленному пользователю вызвать отказ в обслуживании приложения. Уязвимость существует в файле src/profile.c. Удаленный пользователь может вызвать отказ в обслуживании с помощью специально сформированных заголовков сессий. Уязвимость в файле src/find.c позволяет удаленному пользователю вызвать отказ в обслуживании посредством создания указателя на нулевое разыменование. Отказ в обслуживании возможен из-за ошибки в файле gtkedit/editcmd.c при попытке освободить не размещенные в памяти данные. Уязвимость в файле src/key.c позволяет атакующему обратиться к уже освободившейся памяти и вызвать отказ в обслуживании. Удаленный пользователь может вызвать отказ в обслуживании, управляя несуществующими дескрипторами файлов. Уязвимость существует в файле vfs/direntry.c. Уязвимость в файле fish.c позволяет удаленному пользователю выполнить произвольные программы на системе изза недостаточной обработки символов в именах файлов. Переполнение буфера в файле extfs.c позволяет удаленному пользователю вызвать отказ в обслуживании. URL производителя: http://www.ibiblio.org/mc. Решение: Установите обновление: http://savannah.gnu.org/ cgi-bin/viewcvs/mc/mc.
Удаленное выполнение произвольного кода в GNU Queue Программа: Queue 1.30.1. Опасность: Высокая. Описание: Уязвимость позволяет удаленному пользователю выполнить произвольный код на уязвимой системе. Уязвимость обнаружена в файлах queue.c и queued.c. Удаленный пользователь может выполнить произвольный код на уязвимой системе. URL производителя: www.gnu.org/software/queue/queue.html. Решение: На данный момент исправление существует для Linux Debian: http://security.debian.org/pool/updates/main/q/queue.
№1, январь 2005
Выполнение произвольного кода в IBM DB2 Программа: IBM DB2 7.x, 8.1. Опасность: Высокая. Описание: Обнаружено переполнение буфера в IBM DB2. Локальный атакующий может выполнить произвольный код на уязвимой системе. Уязвимость существует в функции generate_distfile. Локальный атакующий может послать функции с помощью db2dbappext.dll специально сформированный третий параметр, вызвать переполнение стека и выполнить произвольный код на уязвимой системе. Уязвимость существует в функции rec2xml. Удаленный атакующий может послать функцию с длинным третьим параметром и выполнить произвольный код на уязвимой системе. URL производителя: http://www-306.ibm.com/software/data/ db2/udb. Решение: Установите обновление: http://www.ibm.com/ software/data/db2/udb/support/downloadv8.html и http:// www.ibm.com/software/data/db2/udb/support/downloadv7.html.
Множественные уязвимости в AntiGen for Domino Программа: AntiGen версии до 7.0 SR5 for Domino, build 745 для Solaris. Опасность: Высокая. Описание: Обнаруженные уязвимости позволяют обойти ограничения при сканировании файлов и вызвать отказ в обслуживании. Уязвимость при обработке вложений в теле MIME может позволить злонамеренному ПО обойти некоторые функции сканирования. Уязвимость при обработке поврежденного MIME-сообщения может позволить злоумышленнику вызвать переполнение буфера. Удаленный пользователь может с помощью специально сформированного сообщения вызвать отказ в обслуживании. Ошибка при сканировании защищенных паролем RARархивов, вложенных в письма, может аварийно завершить работу антивируса. URL производителя: http://www.sybari.com. Решение: Установите обновление: http://www.sybari.com.
Выполнение произвольного кода в telnetd-ssl Программа: telnetd-ssl. Опасность: Высокая. Описание: Уязвимость форматной строки обнаружена в telnetd-ssl. Удаленный атакующий может выполнить произвольный код на уязвимой системе. Уязвимость обнаружена в файле telnetd/telnetd.c при обработке SSL-сообщений. Удаленный атакующий может выполнить произвольный код на уязвимой системе. Решение: На момент публикации решение существует только для Debian Linux.
Составил Александр Антипов
61
программирование
НИТИ В PERL
АЛЕКСЕЙ МИЧУРИН Нити, называемые ещё «легковесными процессами» и управляющими потоками, – это части кода, принадлежащие одному процессу, разделяющие общее адресное пространство, но способные выполняться параллельно и асинхронно, что позволяет разделять вычисления между отдельны-
62
ми процессорами в многопроцессорных системах или продолжать вычисления, пока другие части программы ожидают определённых событий. В настоящей статье рассказывается об организации нитей в Perl, даётся оценка этой, пока достаточно новой и развивающейся, технологии.
программирование threads vs fork Все знают о системном вызове fork, который создаёт точную копию процесса. При этом новый процесс получает своё собственное адресное пространство и начинает существовать независимо от родителя. Такое ветвление процессов – широко распространённая практика в многозадачных средах, способных выполнять сразу несколько потоков команд. Но ветвление – не единственный способ воспользоваться преимуществами многопотоковости. Другой подход – создание нитей (threads). При обычном fork-подходе одно отдельное адресное пространство обрабатывается одним потоком команд. Но согласитесь, что нет никаких принципиальных ограничений на количество потоков команд, работающих в одном адресном пространстве. Такие потоки и принято называть нитями. Нити позволяют операционной системе выполнять программу сразу на нескольких процессорах или продолжать выполнение одной нити, пока другая ожидает ввода/вывода, сетевого соединения или других событий. Подобные возможности доступны и при fork-ветвлении, но нити дают некоторое дополнительное преимущество перед ветвлением. Во-первых, при переключении между нитями системе не приходится менять контекст задачи. Во-вторых, передача данных между нитями происходит гораздо проще, чем между отдельными процессами, благодаря общей памяти. Хотя, конечно, именно «благодаря» этим преимуществам, программирование нитей требует повышенной аккуратности. Но на недостатках нитей я подробно остановлюсь в конце статьи, когда мы поближе познакомимся с тонкостями их функционирования. В этой статье я рассказываю о средствах, имеющихся в Perl, для создания нитей. Конечно, мне не удастся охватить все возможности и тонкости программирования лёгких процессов, но я постараюсь детально остановиться на базовых вопросах и по крайней мере упомянуть средства, расширяющие возможности программиста.
Поддерживаются ли нити вашим Perl? Немного истории. Механизм создания нитей появился ещё в Perl версии 5.005, но первая его реализация обладала массой изъянов. Поэтому в Perl 5.6 появился новый код, названный ithreads, а в версии 5.8 был добавлен интерфейсный модуль, позволяющий создавать нити. Документация настоятельно советует отказываться от старого подхода к созданию и управлению нитями и как можно быстрее переходить на технологию ithreads, т.к. в Perl 5.10 (работа над которым уже идёт) старый подход, скорее всего, не будет поддерживаться. Поэтому я не буду касаться старой технологии управления нитями. Итак, речь пойдёт о самой последней версии Perl 5.8. Но это ещё не всё. Чтобы интерпретатор поддерживал нити, он должен быть собран с соответствующими опциями. Интерпретаторы, поставляемые с разными системами, могут отличаться. Так, например, Perl 5.8, поставляемый с FreeBSD 5.3, не поддерживает нити, и его следует перекомпилировать. Perl, входящий в дистрибутив SuSE Linux 9.1, напротив, собран с поддержкой нитей, и для их использования не требуется никаких дополнительных усилий. Как узнать, способен ли ваш интерпретатор Perl управ-
№1, январь 2005
лять нитями? Посмотреть его настройки командой «Perl -V». Если вы хотите увидеть все характеристики Perl на вашем веб-сервере, то можете выполнить на нём, скажем, вот такой CGI-сценарий. #!/usr/bin/perl use Config; print "Content-Type: text/plain\n\n"; print join "\n", map {$_.' => '. (defined $Config{$_}? ($Config{$_} eq ''? '[EMPTY STRING]': "'$Config{$_}'"): '[UNDEFINED]')} sort keys %Config;
Во всей полученной информации нас будут интересовать две переменные: use5005threads и useithreads. Если обе они не определены, то ваш интерпретатор не может создавать нити. Если определена только первая, значит, ваш интерпретатор поддерживает только старый механизм создания нитей. Если определена только вторая – вы имеете то, что надо, – поддерживается новый аппарат управления нитями. Наконец, если определены обе – это странно; скорее всего, Perl был сконфигурирован некорректно, и ничего работать не будет из-за несовместимости старой и новой технологии. Итак, у вас должен быть Perl версии 5.8, а переменные use5005threads и useithreads должны иметь значения «неопределённое» и define соответственно. Если это так, продолжим изучение механизма ithread.
Создание нитей Интерфейс управления нитями реализован в модуле threads. Для создания нити используется метод create, который требует один обязательный аргумент – ссылку на функцию, за которым может следовать список аргументов. Метод возвращает объект-дескриптор нити. Простейший пример: sub thread_function { print "Ok!\n" } $thread = threads->create(\&thread_function); $thread->join;
В первой строке мы создали нехитрую функцию, во второй – создали дескриптор, в третьей – вызвали нашу функцию. Можно использовать анонимные функции. В нашем примере первые две строки можно объединить в конструкцию: $thread = threads->create(sub { print "Ok!\n" });
Кроме метода create существует и метод new, являющийся просто псевдонимом первого. Поэтому допустим и другой синтаксис: $thread = new threads(sub { print "Ok!\n" });
Все три действия можно, при желании, записать и одной строкой: threads->create(sub { print "Ok!\n" })->join;
Для запуска нити предусмотрено два метода.
63
программирование Первый мы уже видели, это join. Второй – detach. Метод join запускает новую нить, при этом выполнение текущей нити приостанавливается до завершения дочерней, результат работы которой возвращается методом join в запускающую нить. Приведу простой пример: #!/usr/bin/perl -w use strict; use threads; sub f { my ($a)=@_; print "WAIT $a\n"; sleep 1; print "DONE $a\n"; return "RESULT $a\n"; } my $a = threads->create(\&f, 'A'); my $b = threads->create(\&f, 'B'); print $a->join; print $b->join;
Как вы видите, наша функция &f получает один аргумент, печатает фразу «WAIT »+аргумент, ждёт одну секунду, печатает «DONE »+аргумент и возвращает результат – строку «RESULT »+аргумент. Мы создаём две нити. Дескриптор $a соответствует нити, выполняющей функцию &f с параметром «A», а $b – «B». Далее мы запускаем обе нити. Как вы думаете, сколько времени потребуется на выполнение программы? Правильно, чуть больше одной секунды, т.к. оба ожидания будут идти практически одновременно! В результате мы получим следующий вывод: WAIT A WAIT B DONE A RESULT A DONE B RESULT B
То есть произошёл запуск нити A, она напечатала первую строку и «заснула» на секунду. Не дожидаясь пробуждения A, началось выполнение нити B (строка «WAIT B»). Пока B спала, проснулась A и вывела результат на печать. Далее проснулась B. Когда все нити отработали, программа завершилась. Давайте чуть усложним наш код: #!/usr/bin/perl -w use strict; use threads; sub f { my ($a, $t)=@_; print "WAIT $a\n"; sleep $t; print "DONE $a\n"; return "RESULT $a\n"; } my $kida = threads->create(\&f, 'A', 2); my $kidb = threads->create(\&f, 'B', 1); print $kida->join; print $kidb->join;
Теперь нить A выполняется две секунды, а нить B – попрежнему одну.
64
Результат будет таков: WAIT A WAIT B DONE B DONE A RESULT A RESULT B
Вы видите, что нить В отработала быстрее, но первый оператор print не выполнялся, пока нить A не завершила работу. Не мог выполниться и второй оператор print, хотя результат уже был готов. Метод detach работает иначе. Запущенная нить становится полностью автономна, а запускающий код продолжает выполняться, не дожидаясь её завершения. Поэтому метод detach не возвращает результат работы; последний просто теряется.
Несколько слов о других возможностях модуля threads Модуль thread содержит ещё несколько полезных функций. Название метода threads->self говорит само за себя, он возвращает дескриптор текущей нити. Метод threads->tid возвращает более удобный целочисленный идентификатор текущей нити. Каждая нить получает свой уникальный идентификатор. Основная программа является нитью номер ноль. Метод threads->object($tid) возвращает дескриптор, соответствующий идентификатору, или undef, если нити с заданным $tid не существует. Метод threads->yield (теоретически) сообщает операционной системе, что текущая нить может уступить остаток кванта времени, выделенного ей, другому процессу или нити. Эта функция может быть весьма полезна, но фактически она реализована далеко не во всех операционных системах и зачастую просто не производит никаких действий. И наконец, метод threads->list возвращает список объектов, которые уже созданы методом create (или new), но пока не были запущены ни методом join, ни detach.
Доступ к глобальным переменным При беглом взгляде на следующий пример может показаться, что глобальные переменные доступны для нитей. Это не совсем так. Чтобы прояснить ситуацию, предлагаю запустить следующий код: #!/usr/bin/perl -w use strict; use threads; my $a; sub f { my $aa=$a; $a=7; return "DONE (a=$aa)\n" } $a=0; my $kida = threads->create(\&f); $a=1; my $kidb = threads->create(\&f); $a=2; print print $a=3; print print
"(a=$a)\n"; $kida->join; "(a=$a)\n"; $kidb->join;
программирование Несмотря на использование ключа -w и модуля strict, ни ошибок, ни предупреждений этот пример не вызовет. То есть глобальная переменная $a доступна в функции &f. Но давайте посмотрим, что же выдаст эта программа: (a=2) DONE (a=0) (a=3) DONE (a=1)
Удивлены? Ничего странного, функция &f, выполняемая в нити, видит то значение глобальной переменной, которое имелось на момент создания нити (вызов create). Дело в том, что при создании нити методом create или new происходит копирование всех глобальных переменных в локальный контекст нити, с которым она и работает. Поэтому изменение значения $a в коде нити (в функции &f) никак не влияет на значение $a, которое доступно из основной программы или из других нитей. Именно поэтому нити рекомендуется создавать как можно раньше, пока программа не успела аккумулировать большой объём данных; не следует перегружать код глобальными переменными. Иначе создание нити, вернее копирование данных (очень скоро мы убедимся, что это не совсем копирование «один к одному»), может занять десятки (!) секунд и привести к существенному перерасходу памяти. Справедливости ради надо сказать, что я не замечал за нитями утечек памяти. Копия глобальных переменных уничтожается сразу после завершения работы нити. Создание копии данных имеет ещё одно побочное действие – изменение значений указателей. Взгляните на следующий пример: #!/usr/bin/perl -w use strict; use threads; my $a; my $b=\$a; sub f { print "in thread b=$b\n" } my $kid = threads->create(\&f); print "in main $kid->join;
Модуль thread::share предоставляет все необходимые средства для создания разделяемых переменных и корректной работы с ними. Он может использоваться только в сочетании с модулем threads. В противном случае все методы модуля thread::share не выполняют никаких действий. Разделяемые переменные создаются функцией share, аргументом которой может быть скаляр, массив, хэш или указатель на любой из этих типов данных. Функция делает аргумент разделяемым и возвращает ссылку на него. Например: # ñîçäà¸ì ðàçäåëÿåìûé ñêàëÿð my $a; share($a); # ñîçäà¸ì ðàçäåëÿåìûé ìàññèâ my @a; share(@a); # ñîçäà¸ì ðàçäåëÿåìûé õýø my %a; share(%a); # óêàçàòåëü íà ðàçäåëÿåìûé ìàññèâ my $a=&share([]); # óêàçàòåëü íà ðàçäåëÿåìûé õýø (!) my $a=&share();
Share имеет несколько специфических особенностей. Во-первых, в последних двух командах этого примера следует обязательно использовать полное имя функции &share с явным указанием типа. Во-вторых, разыменование ссылок осуществляется только на один уровень. То есть share($a) эквивалентно share(\$a), но не эквивалентно share(\\$a). В-третьих, обобществление массивов и хэшей приводит к обобществлению всех их элементов и ключей. В-четвёртых, и это очень существенно, разделяемой переменной можно присваивать только простые значения и ссылки на другие разделяемые переменные. Таким образом, нить по-прежнему не может получить доступ к простым глобальным переменным даже через указатель на таковые, сохранённый в разделяемой переменной. Вот иллюстрация: my $a; share($a); my $b; $a=\$b;
b=$b\n";
В результате его работы мы получим нечто подобное: in thread b=SCALAR(0x8237bb8) in main b=SCALAR(0x81691e8)
Как видите, мы создали глобальный указатель $b на глобальную переменную $a. В основной программе и внутри нити указатель имеет разные значения. В первом случае он хранит адрес переменной $a, во втором – адрес копии $a, созданной в момент создания нити. Именно это я имел в виду, когда говорил, что копирование глобальных переменных – это не совсем копирование. Значение ссылки будет изменяться даже при передаче её в качестве аргумента. Таким образом, Perl не позволяет обмануть его и закрывает все возможные лазейки для доступа к одним и тем же глобальным переменным из разных нитей. Для разделения данных существует специальный набор инструментов.
№1, январь 2005
Разделение данных
Последняя строка приведёт к ошибке: «Invalid value for shared». Ошибки не возникнет, если мы чуть изменим код, сделав $b разделяемой: my $a; share($a); my $b; share($b); $a=\$b;
Последнее, что следует сказать о создании разделяемых переменных, это то, что их можно создавать на этапе компиляции программы, указывая атрибут shared: my $a : shared = 1;
Проблемы, возникающие при работе с разделяемыми переменными Потенциальные трудности, связанные с разделяемыми переменными, проще проиллюстрировать примером:
65
программирование #!/usr/bin/perl -w use strict; use threads; use threads::shared; my $a : shared = 0; sub f { my $c=$a; $c++; $a=$c; } my $p=threads->create(\&f); my $q=threads->create(\&f); $p->join; $q->join; print "$a\n";
Как видите, каждый вызов нити должен увеличивать $a на единицу. Мы вызываем нить дважды, но увидим ли мы в результате двойку? Совсем не обязательно! Обе нити выполняются параллельно, и может сложиться такая ситуация, что локальные переменные $c будут инициализированы до того момента, когда хотя бы одна из нитей изменит значение общей переменной $a. Тогда обе $c будут равны нулю, после инкремента – единице, и $a получит значение один. Это произойдёт почти наверняка, если чуть модифицировать функцию &f: sub f { my $c=$a; sleep 1; $c++; $a=$c; }
Более того, даже простой инкремент нельзя считать атомарной (неделимой) операцией. И даже если мы изменим &f следующим образом: sub f { $a++ }
Результат по-прежнему будет зависеть от того, как операционная система распределит процессорное время между разными нитями. То есть фактически он будет непредсказуем.
Блокировка переменных Для разрешения подобных проблем модуль threads::shared предлагает различные средства блокировки. Наиболее часто используется функция lock. Эта функция блокирует переменную в пределах её области видимости. То есть в пределах блока, ограниченного фигурными скобками. Если переменная заблокирована одной нитью, то вызов lock для этой же переменной в другой нити вызовет приостановку выполнения этой нити до тех пор, пока первая нить не снимет блокировку. Корректно функцию &f в нашем примере можно переписать так: sub f { lock($a); $a++; }
Если необходимо изменить две переменные, то совсем не обязательно блокировать обе на всё время выполнения функции. Достаточно разнести действия с каждой из переменных в отдельные блоки и выполнять блокировку в каждом из них только одной переменной (конечно, если алгоритм допускает подобное разделение).
66
Пример: sub f { { lock($a); $a++ } { lock($b); $b++ } # çàáë. òîëüêî $b }
Но при работе с несколькими разделяемыми переменными следует соблюдать определённую технику безопасности, чтобы избежать ситуации, называемой в англоязычных источниках deadlock (что я бы перевёл, как блокировка намертво). Вот пример такой ситуации: #!/usr/bin/perl -w use strict; use threads; use threads::shared; my $a : shared; my $b : shared; my $p=threads->create( sub { lock($a); sleep 1; lock($b) } ); my $q=threads->create( sub { lock($b); sleep 1; lock($a) } ); $p->join; $q->join;
Эта программа, скорее всего, зависнет «намертво». Причина проста: обе нити выполняются практически одновременно. Каждая блокирует одну из двух переменных (первый вызов lock), а потом обе ждут, когда будет снята блокировка другой переменной (второй вызов lock). Ни одна не может уступить, и весь конгломерат «зависает» в нескончаемом ожидании. Надёжной стратегией, позволяющей избежать таких ситуаций, является строгое соблюдение порядка установки блокировок. Допустим, всегда блокировать $a раньше, чем $b; и никогда иначе. У блокировки есть несколько важных свойств. Во-первых, важно понимать, что lock действует аналогично системной функции flock, обеспечивающей блокировку файлов. Она не ограничивает использование переменной, а только блокирует выполнение других вызовов lock. Это похоже на светофор, который лишь указывает на возможность или невозможность движения, но не способен остановить нарушителя. Во-вторых, повторный вызов lock для той же переменной в той же области видимости не выполняет никаких действий: { lock($x); lock($x); }
В этом примере второй вызов lock не выполнит никаких действий. Программа продолжит работу. В-третьих, при вызове других функций заблокированные переменные остаются таковыми же: sub a { $x++; # $x îñòàëàñü çàáëîêèðîâàíà } sub b { lock($x); a(); }
программирование Другие возможности модуля use threads::shared Модуль содержит ещё несколько очень полезных инструментов, связанных с блокировкой. Очень коротко расскажу про них. За более подробной информацией обращайтесь к руководству perldoc threads::shared. Функция cond_wait служит для временного снятия блокировки с переменной. Допустим, вы заблокировали переменную, но хотите временно предоставить к ней доступ другим нитям. Тогда вы вызываете cond_wait. Блокировка с переменной снимается, и выполнение cond_wait приостанавливается. Теперь ваша нить ждёт, пока другая нить проделает необходимые манипуляции с переменной. Когда работа с переменной завершена, нить (выполнявшая действия) должна сообщить о том, что переменная ей больше не нужна, вызвав функцию cond_signal для этой же переменной. Тогда cond_wait снова блокирует переменную и завершается, позволяя первой нити продолжить работу. Допустим вызов функции cond_wait с двумя параметрами. Тогда она снимает блокировку со второго и ждёт, когда поступит сигнал для первого аргумента. Функция cond_timedwait выполняет аналогичные действия, но позволяет задать тайм-аут. Она также снимает блокировку и ждёт сигнала или наступления тайм-аута. Если наступил тайм-аут, cond_timedwait возвращает ложь, если был получен сигнал – истину. Функцию cond_timedwait можно вызывать и с тремя аргументами, тогда она действует аналогично cond_wait с двумя аргументами, но отслеживает ещё и тайм-аут. Для отправки сигналов существует две функции: cond_ signal и cond_broadcast. Обе получают один аргумент – переменную и посылают сигнал для cond_wait. Разница состоит только в том, что если сразу несколько нитей ожидают сигнала, то cond_signal посылает сигнал только одной из них (причём неизвестно, какой), а cond_broadcast посылает сигнал всем. Использование системы сигналов (как и многие вопросы, затрагиваемые в этой статье) вполне заслуживает отдельной книги. Неаккуратность может привести к зависаниям и другим неприятным последствиям. Я не буду здесь подробно останавливаться на вопросах низкоуровневой синхронизации параллельных процессов и позволю себе перейти к рассмотрению более высокоуровневых и менее прихотливых средств.
Семафоры Классическим средством синхронизации являются семафоры. Для нитей они реализованы в модуле Thread::Semaphore, который предоставляет всего три функции: new – создать семафор, down – опустить семафор (в железнодорожном понимании – закрыть проезд), up – поднять семафор. Проще всего представить семафор как счётчик. Функция up увеличивает счётчик на единицу. Функция down уменьшает счётчик на единицу, и если счётчик становится равен нулю (или меньше), то down останавливается и ждёт, когда семафор поднимется. Так семафоры сигнализируют, занят ресурс или свободен, и позволяют ехать по рельсам только одному паровозу (для всех других семафор закрыт). Помните наш пример, демонстрирующий, какие пробле-
№1, январь 2005
мы возникают, если не блокировать разделяемые переменные? Тогда мы спасли ситуацию, использовав функцию lock, но выйти из положения можно было и обратившись к аппарату семафоров. Вот пример безопасного кода, не использующего функцию lock; обходящего возможные проблемы только средствами семафоров: use threads; use Thread::Semaphore; my $s = new Thread::Semaphore; my $a : shared = 0; sub f { $s->down; $a++; $s->up; } my $p=threads->create(\&f); my $q=threads->create(\&f); $p->join; $q->join; print "$a\n";
Подобную защиту можно было реализовать на основе cond_wait/cond_signal, но эта пара функций связана с блокировкой переменных, а семафоры заслуживают особого внимания, так как они гораздо универсальней. С этой универсальностью связано их следующее замечательное свойство. Все три метода – new, up и down – можно вызывать с аргументом. Это должно быть целое число, которое new интерпретирует как начальное значение счётчика, а up и down – как величину, на которую следует изменить счётчик. На первый взгляд кажется, что семафор, созданный методом new с аргументом 3, – сломанный семафор. Но если присмотреться, то оказывается, что он позволяет ехать одновременно не более чем трём паровозам. Это очень полезно, когда речь идёт не о переменных, хранящихся в памяти, а о ресурсах, допускающих одновременное коллективное использование, но требующих определённой экономии. Примером такого ресурса может быть сетевой канал. Вы можете ограничить количество нитей, работающих с каналом, но ограничить его не единицей, а любым числом! В некоторых случаях это делает семафоры гораздо привлекательнее, чем блокировки. Для тех, у кого ещё осталось недопонимание, приведу пример: use threads; use Thread::Semaphore; $|=1; my $s = Thread::Semaphore->new(2); my $a : shared = 0; sub f { my ($name, $time, $greed)=@_; print "$name: Ïûòàþñü îïóñòèòü ñåìàôîð, çàõâàòèâ ↵ $greed øò. ðåñóðñîâ\n"; $s->down($greed); print "$name: Ñåìàôîð îïóùåí, ðàáîòàþ ñ ↵ $greed øò. ðåñóðñîâ $time ñ.\n"; sleep $time; print "$name: Ïîäíèìàþ ñåìàôîð\n"; $s->up($greed);
67
программирование {lock($a); $a++} } foreach (qw/A B C D E F/) { threads->create(\&f, $_, 1+int(rand(3)), ↵ 1+int(rand(2)))->detach; } for (my $i=0; $a<6; $i++) { print "Èä¸ò ñåêóíäà $i\n"; sleep 1; }
Здесь мы создаём семафор, позволяющий сразу двум нитям использовать одновременно некий воображаемый ресурс. Потом мы создаём шесть нитей, задавая им случайные аргументы. Каждая оккупирует ресурс на несколько секунд и в разном объёме: некоторым необходима одна единица ресурса, некоторым – две. После запуска нитей запускается цикл – таймер, ожидающий завершения всех нитей. Чтобы Perl выдавал сообщения незамедлительно, нам пришлось отключить буферизацию $|=1. Вот какой вывод мы получим (естественно, он будет получаться всегда немного разный, оттого что мы используем для инициализации случайные числа):
гумент – скаляр или список), метод dequeue извлекает данные из очереди. my $q=Thread::Queue->new; $q->enqueue('text'); $q->enqueue(1, 2, 3); my $var=$q->dequeue;
Причём, если очередь пуста, то метод dequeue ждёт, пока в очереди не появятся данные. Приведу простой пример использования очередей: #!/usr/bin/perl -w use strict; use threads; use Thread::Queue; my $q=Thread::Queue->new; sub f { $q->enqueue("I'm going sleep"); sleep 1; $q->enqueue("I'm waiking up"); $q->enqueue(undef); } my $p=threads->create(\&f);
A: Пытаюсь опустить семафор, захватив 2 шт. ресурсов A: Семафор опущен, работаю с 2 шт. ресурсов 1 с. B: Пытаюсь опустить семафор, захватив 1 шт. ресурсов C: Пытаюсь опустить семафор, захватив 1 шт. ресурсов D: Пытаюсь опустить семафор, захватив 2 шт. ресурсов E: Пытаюсь опустить семафор, захватив 2 шт. ресурсов F: Пытаюсь опустить семафор, захватив 2 шт. ресурсов Идёт секунда 0 A: Поднимаю семафор B: Семафор опущен, работаю с 1 шт. ресурсов 1 с. C: Семафор опущен, работаю с 1 шт. ресурсов 2 с. Идёт секунда 1 B: Поднимаю семафор Идёт секунда 2 C: Поднимаю семафор D: Семафор опущен, работаю с 2 шт. ресурсов 3 с. Идёт секунда 3 Идёт секунда 4 Идёт секунда 5 D: Поднимаю семафор E: Семафор опущен, работаю с 2 шт. ресурсов 1 с. Идёт секунда 6 E: Поднимаю семафор F: Семафор опущен, работаю с 2 шт. ресурсов 3 с. Идёт секунда 7 Идёт секунда 8 Идёт секунда 9 F: Поднимаю семафор
Как видите, мы достигли поставленной цели: наш набор нитей использует одновременно не более чем две единицы ресурса. Обратите внимание, что мы могли захватывать и освобождать ресурсы постепенно даже в пределах одной нити. Заметьте также, что подобная практика может привести к зависанию одной из нитей, если аргумент down больше аргумента new. Получается, что нить требует больше ресурсов, чем дозволено использовать вообще. Такая нить будет вечно ждать благоприятных условий.
Очереди Очереди позволяют передавать данные между нитями, не заботясь ни о синхронизации, ни о блокировке. Модуль Thread::Queue предоставляет полный набор инструментов для работы с очередями: новая очередь создаётся методом new, метод enqueue помещает данные в очередь (ар-
68
$p->detach; while (my $t=$q->dequeue) { print "He say: '$t'\n"; }
Здесь нить асинхронно помещает данные в очередь, а основная программа (нить номер ноль) «прослушивает» эту очередь. Я бы хотел обратить ваше внимание на несколько аспектов. Во-первых, нам не только не пришлось заботиться о блокировке переменных и передаче/приёме сигналов, но и вообще не понадобилось подключать модуль threads::share и обращаться к разделяемым переменным – мы вполне обошлись глобальными. Это не значит, что все сложности, возникающие при работе с глобальными переменными, описанные выше, исчезли. Это значит только то, что модуль Thread::Queue обходит их сам. Во-вторых, так или иначе, но при подобном обмене данных следует соблюдать определённый протокол. В нашем случае появление в очереди ложного значения сигнализирует процессу-получателю об окончании передачи. Если бы мы не поместили в очередь заключительное undef, наша программа просто зависла бы в ожидании новых данных в очереди. В документации perldoc perlthrtut есть очень интересный пример. Программа ищет простые числа; всё написано на нитях и очередях. Предложенный там код выгодно отличается от моих примитивных примеров, приводимых в этой статье. Для компактности и максимальной наглядности я в своих примерах создаю только столько нитей, сколько необходимо для демонстрации той или иной возможности, передавая функциям аргументы-константы. Пример в perlthrtut порождает нити в том количестве, какое необходимо, динамически разветвляя процесс вычислений (более ста штук, если ничего не менять). Я бы с удовольствием рассмотрел здесь подобный пример, но боюсь, что эта за-
программирование дача не сможет уложиться в рамки журнальной статьи. Тем не менее приведённых здесь фактов более чем достаточно, чтобы понять, как работает пример из perlthrtut. К тому же он снабжён краткими, но исчерпывающими комментариями (на английском языке). Рекомендую взглянуть на него всем, кто заинтересовался.
Обеспечение совместимости и переносимости кода Как вы уже могли убедиться, не все реализации (сборки) интерпретатора Perl поддерживают нити. В программе, требующей работы с нитями, уместно предусмотреть хотя бы элементарную проверку. Например, такую: ... use Config; ... die "ß ðàáîòàþ òîëüêî ñ íèòÿìè\n" unless ($Config{'useithreads'}); ...
Удачной идеей будет изолировать весь threads-зависимый код в отдельный модуль. А полной переносимости можно достичь, если создать модуль-дублёр, выполняющий те же функции, но не требующий поддержки нитей. Тогда можно подключать тот или другой модуль, в зависимости от конкретной ситуации: use Config; BEGIN { if ($Config{'useithreads'}) { require my_threads_dep; import my_threads_dep; } else { require my_threads_indep; import my_threads_indep; } }
Функция import не является встроенной функцией Perl. Эту функцию традиционно содержит модуль. Возможно, для подключения вашего модуля будет достаточно оператора require.
И снова threads vs fork. Отличие нитей от ветвления Теперь, когда мы уже знакомы с особенностями нитей, давайте подведём некоторые итоги: чем лёгкие процессы отличаются от обычных дочерних процессов. Мы уже много говорили о преимуществах, давайте просуммируем и недостатки. Основное обстоятельство, накладывающее серьёзные ограничения на производительность нитей, то, что каждая из них получает копию всех данных, доступных родителю. Впрочем, дочерние процессы, порождённые с помощью fork, тоже получают копию данных родителя. Создание такой копии приводит не только к излишнему расходу памяти, но и к существенным затратам процессорного времени. Мы уже видели, что при «копировании» Perl выполняет ряд дополнительных действий, например, корректирует ссылки. К счастью, вы можете свести эти затраты практически к нулю, ограничив количество глобальных переменных или полностью отказавшись от таковых. Это, как известно, вообще хороший стиль программирования.
№1, январь 2005
Следует заметить, что разделяемые переменные требуют немного больше памяти и работают чуть медленнее обычных. Следующее ограничивающее обстоятельство напрямую следует из того, что все нити принадлежат одному процессу, а стало быть, могут изменять контекст выполнения процесса, и эти изменения будут касаться всех нитей. Поэтому в нитях следует избегать команд, влияющих на контекст процесса, таких как chdir (смена текущего рабочего каталога), chroot (смена корневого каталога), umask (смена маски атрибутов файлов), а также команд, изменяющих идентификатор пользователя и группы, и прочих подобных действий. Небезопасными вызовами являются exit и другие, приводящие к завершению программы. Такой вызов может сделать любая нить, но при этом завершится программа и все нити будут аварийно остановлены. Если Perl приходится останавливать сразу несколько нитей, то он выдаёт предупреждение. Некорректно в нитях могут работать и функции rand и srand, функции работы с временем и даже с сетевыми интерфейсами, так как эти функции могут быть связаны с глобальным окружением процесса. Если вы хотите использовать эти функции, то в первую очередь обратитесь к документации на вашу систему. Также неудачной идеей является сочетание fork- и threads-подходов. В разных операционных системах реализации fork- и thread-механизмов могут очень сильно отличаться. Совместное использование этих двух подходов может привести к непредсказуемым результатам. Самый простой вопрос: должен ли процесс, порождённый вызовом fork, наследовать все нити родителя, или он станет копией только одной вызывающей нити? Ответ на этот вопрос различен для разных операционных систем. По тем же причинам не следует использовать сигналы (системный вызов kill) для синхронизации нитей. При работе с файлами следует соблюдать обычные в таких случаях меры предосторожности. Блокировать дескрипторы (системный вызов flock), своевременно сбрасывать буферы. Одним словом, нити гораздо более капризны, чем дочерние процессы. Технологию создания нитей нельзя считать столь же зрелой и стандартизованной, как технологию порождения дочерних процессов. И прежде чем вы начнёте использовать нити в больших проектах, обязательно ознакомьтесь со страницами документации perldoc threads, threads::shared, Thread::Queue, Thread::Semaphore, perlthrtut (в которой дано несколько дополнительных ссылок) и документацией на вашу операционную систему. Не помешает и потестировать критичные узлы отдельно, прежде чем вносить окончательные изменения. Техника использования легковесных процессов, как вы видите, ещё очень молода, и использовать её следует со всей возможной осторожностью. Но с увеличением доли многопроцессорных машин она, безусловно, будет совершенствоваться, развиваться и стандартизироваться. А при аккуратном использовании она позволяет уже сейчас качественно усовершенствовать ваши программы, значительно повысив их производительность.
69
web
JpGraph ДИНАМИЧЕСКАЯ ГРАФИКА – ЭТО ПРОСТО
КИРИЛЛ СУХОВ Ещё каких-то лет пять назад человек, занимающийся разработкой сайтов, мог гордо именовать себя веб-мастером, не вызывая при этом иронических усмешек у коллег. В это понятие входили дизайн, вёрстка, веб-программирование, и в объявлениях о приёме на работу часто мирно уживались требования по знанию Perl и Photoshop. Теперь, разумеется, многое изменилось, и в резюме веб-программиста считается дурным тоном упоминать навыки работы с графическими пакетами, даже если таковые и присутствуют. Тем не менее если вы работаете в небольшом проекте, в бюджете которого не предусмотрен многочисленный штат сотрудников, то время от времени у вас может возникнуть необходимость в самостоятельном создании кое-какой графики – кнопочек, маркеров, пиктограмм, фоновых изображений, которые нужны для любого веб-интерфейса. В общем случае такие задачи решаются использованием готовой библиотеки изображений или приглашением знакомого дизайнера (как правило, за солидный гонорар – две, а то и три бутылки пива). Проблема, решение которой изложено ниже, не так стандартна и немного сложнее, хотя встречается не так уж редко. Итак, представим, что вы разрабатываете/ведёте биллинг, или складскую систему, или… в общем, приложение, использующее базу данных и несущее достаточно сложную логику. Представим также (хотя это и сложнее), что никаких особых проблем у вас нет – приложение работает корректно, новая функциональность добавляется относительно легко, небольшие корректировки много времени не отнимают. В целом вы довольны, но кроме вас в офисе трудятся менеджеры, бухгалтеры, начальство, и вот у последнего возникают довольно своеобразные требования. В частности, шефа не устраивают ваши отчёты, генерирующиеся в виде аккуратных HTML-таблиц, ему нужны графики, причём графики красивые и ежедневно (ежечасно?!) обновляющиеся. Не рисовать же их руками? К счастью, PHP-разработчик может воспользоваться таким мощным инструментом, как графическая библиотека GD, включаемая по умолчанию в дистрибутив, начиная с версии 4.0.1. Возможность попиксельной прорисовки и обработки изображения, манипуляции с размером картинки и текстом, наличие примитивов позволяют генерировать достаточно сложную графику. Проблема заключается в том, что на построение качественного графика или диаграммы уйдет довольно много времени, а наша задача в данном случае – справиться с поручением в сжатые сроки и с ми-
70
нимальным количеством кода. Существует некоторое количество готовых библиотек для разработки графиков, например, автор этих строк в своё время использовал довольно удачную разработку – phplot (http://www.phplot.com), но безусловным лидером в этом отношении является объектно-ориентированная библиотека JpGraph. Среди её преимуществ можно выделить возможность построения множества видов графиков, неограниченного числа графиков одного типа в одном изображении, сглаживание линий, заполнение фонов диаграмм и гистограмм градиентной заливкой, генерация карт-изображений и кэширование рисунков. Стандартная версия библиотеки бесплатна (существует и коммерческая версия pro, в которой доступны некоторые дополнительные возможности, в частности, построение штрих-кодов). В статье речь пойдет о стандартной версии, о возможностях коммерческой читатель может ознакомиться на сайте производителя – http://www.aditus.nu/ jpgraph/jpg_proversion.php. Ещё одним достоинством этого продукта является прекрасная документация, идущая вместе с дистрибутивом. На самом деле подробность документации ставит под сомнение необходимость чтения этой статьи, но автор этих строк, как наверняка и кто-нибудь из вас, попадал в ситуацию, когда времени на обстоятельное изучение руководства просто нет, и я попытался изложить этот материал для того, чтобы программист по его прочтении мог немедленно приступить к работе.
Постановка задачи Для примера возьмём вполне реальную проблему из практики небольшого интернет-провайдера. Необходимо написать скрипт, строящий график распределения входящего трафика по дням за определённый период (скажем, за последние десять дней). Естественно, график должен строиться динамически и генерироваться по запросу на внутреннем веб-сайте компании. Будем считать, что веб-сервер с поддержкой PHP уже установлен. Все нижеописанные действия проводились на веб-сервере Apache версии 1.3.31 (Win32), работающем под управлением Windows 2000 Server. Версия интерпретатора PHP – 4.3.9 с поддержкой библиотеки GD2, версии 2.0.28. PHP был установлен как модуль.
Инсталляция В целом установка библиотеки JpGraph никаких сложностей не вызовет. Нужно просто скачать архив с библиотекой,
web расположенный по адресу http://www.aditus.nu/jpgraph.php, и распаковать его в папку документов вашего веб-сервера. До установки следует убедиться, что PHP у вас версии не ниже 4.01 (рекомендуется 4.3х) и скомпилирован с поддержкой библиотеки GD (для доступа к последним возможностям JpGraph, GD2). Графические форматы, с которыми работает библиотека, определяются возможностями установленной GD и автоматически выбираются JpGraph в следующем порядке: «PNG», «GIF», «JPG». Для проверки установки GD руководство по JpGraph рекомендует следующий простой сценарий: $im = ImageCreate (50, 100) or die ("Cannot create a new GD image."); $background_color = ImageColorAllocate ($im, 255, 255, 255); $text_color = ImageColorAllocate ($im, 233, 14, 91); ImageString ($im, 1, 5, 5, "A Simple Text String", $text_color); header ("Content-type: image/png"); ImagePng ($im);
тыка» подогнать его под свои нужды. Когда передо мной встала необходимость быстро построить график, я так и сделал, но, разумеется, для полноценной работы с библиотекой необходимо разобраться в её свойствах и методах, поэтому далее мы будем строить график «с нуля».
Приступаем к работе (простой график) Прежде всего определимся с исходными данными. Разумеется, в реальных условиях они будут извлекаться из базы данных, но чтобы не усложнять задачу, мы просто создадим два массива, первый из которых будет состоять из чисел месяца, а второй – из соответствующих им показателей входящего трафика. <? $traff = array(350, 280, 450, 615, 588,755, 547,320, ↵ 380, 810); // òðàôèê (Ìá) $days = array (9, 10, 11, 12, 13, 14, 15, 16, 17, 18); // äàòû ?>
Для построения графика используем следующий код: Если тест прошёл удачно и изображение было создано, можно устанавливать библиотеку и начинать работу, но для реализации поставленной задачи необходимо выполнить ещё несколько действий. Прежде всего вы должны обеспечить поддержку TTF-шрифтов (они нам обязательно понадобятся, об этом далее). Для этого PHP должен быть собран с поддержкой TTF, а также с FreeType 1 или FreeType 2 библиотеками, и несколько (как минимум два) шрифтов установлены в системе. Следующий этап – настройка нелатинских шрифтов. Понятно, что в данном случае необходимости в китайских символах у нас нет, а для использования кириллицы необходимо отредактировать файл jpg-config.inc. В нём имеются следующие настройки:
include ("../jpgraph.php"); include ("../jpgraph_line.php"); $graph = new Graph(450, 200,"auto"); $graph->SetScale( "textlin"); $lineplot =new LinePlot($traff); $graph->Add( $lineplot); $graph->Stroke();
Если всё установлено правильно, в результате должна получиться картинка, показанная на рис. 1 (пример дан в предположении, что ваш скрипт test.php расположен в папке src/examples/, если это не так, отредактируйте пути к библиотеке).
// Special unicode cyrillic language support DEFINE("LANGUAGE_CYRILLIC",false); // If you are setting this config to true the conversion // will assume that the input text is windows 1251, if // false it will assume koi8-r DEFINE("CYRILLIC_FROM_WINDOWS",false);
После установки значений обоих параметров в true необходимо убедиться, что на сервере имеются стандартные юникодные шрифты (обычно они лежат в директории типа /usr/X11R6/lib/X11/fonts/TTF/) и проверить, поддерживают ли они кириллицу. В случае их отсутствия шрифты следует установить, например с Windows-машины (должен заметить, что при установке под Windows проблем с кириллицей вообще не возникает). После этого в том же файле jpg-config.inc следует прописать путь к шрифтам: DEFINE('TTF_DIR',…);
Теперь всё готово. Для проверки и ознакомления с возможностями инструмента раскроем в браузере файл src/ examples/testsuit.php из дистрибутива библиотеки. Мы увидим около трёхсот графиков диаграмм и рисунков, кликнув по каждому из которых, можно увидеть исходный код примера. Самый лёгкий способ начать работу с библиотекой – взять наиболее подходящий пример и методом «научного
№1, январь 2005
Ðèñóíîê 1
Конечно, это ещё довольно далеко от желаемого результата, но давайте сначала разберёмся в том, что мы уже сделали. В первых двух строчках кода мы подключаем базовую библиотеку jpgraph.php и один из модулей (plot extensions), в данном случае это jpgraph_line.php, необходимый для построения линейных графиков. Затем создаём объект класса Graph, задав его размеры, и выбираем масштаб оси X (метод SetScale()). Потом создается объект класса plot (график), параметры которого задаются созданным нами ранее массивом, сохранённым в переменной $traff. В последних двух строчках график добавляется в объект Graph и методом Stroke() Graph выводится в браузер. Данные по оси X должны соответствовать реальным датам. Для этого добавим строчку: $graph->xaxis->SetTickLabels($days);
71
web Теперь добавим заголовок и подписи к осям (для чего нам понадобится устанавливать шрифты). $graph->title->SetFont(FF_VERDANA,FS_NORMAL,12); $graph->xaxis->title->SetFont(FF_VERDANA,FS_NORMAL,8); $graph->yaxis->title->SetFont(FF_VERDANA,FS_NORMAL,8); $graph->title->Set("Òðàôèê"); $graph->xaxis->title->Set("Ïåðèîä"); $graph->yaxis->title->Set("Òðàôèê (Mb)");
Задача в первом приближении выполнена.
Ðèñóíîê 2
Теперь осталось добавить удобочитаемость. Выполняем следующие действия. Устанавливаем отступы и поля для подписи к оси Y (поскольку с ней проблемы): $graph->SetMargin(60,40,40,40); $graph->yaxis->SetTitlemargin(40);
Добавляем маркеры и подписи к ним: $lineplot->mark->SetType(MARK_IMG_DIAMOND, 'blue', 0.3); $lineplot->value->Show() ; $lineplot->value->SetColor("darkgray"); $lineplot->value->SetFont(FF_FONT0,FS_BOLD); $lineplot->value->SetFormat(" %01.0f Mb");
«Раскрашиваем» график, добавляем фон и тень: $lineplot ->SetColor("blue"); $graph->SetColor('cadetblue1'); $graph->SetMarginColor('lightblue3'); $graph->SetShadow();
По-моему, в результате получился вполне симпатичный график.
Ðèñóíîê 3
Полный код, генерирующий эту картинку, приведен на сайте журнала http://www.samag.ru/source. Всё, что осталось сделать, – это сохранить весь код в файле (например, my_graph.php) и в нужном месте веб-страницы вставить тег рисунка с указанием на этот файл (<img src=”my_graph.php”).
72
Что внутри? Теперь давайте разберёмся с внутренним устройством библиотеки. Как уже было упомянуто, для построения любого изображения необходимо включить в сценарий основной модуль – файл jpgraph.php и один или несколько модулей, ответственных за построение изображения требуемого типа. Все они содержатся в папке \src, хотя могут быть перенесены оттуда в любое удобное для вас место. (При этом, разумеется надо соблюдать некоторые зависимости. Так, внутренний модуль jpgraph_gradient.php никогда явно не подключается к сценарию, но используется другими модулями и без него не обойтись при генерации любого изображения, использующего градиентную заливку.) Ниже перечислены основные модули. ! jpgraph_line.php – уже знакомое нам расширение для построения линейных графиков. ! jpgraph_bar.php – модуль для построения баров (гистограмм). ! jpgraph_log.php – модуль для отображения логарифмических зависимостей. ! jpgraph_error.php – модуль для вывода графических сообщений об ошибках (для чего это нужно – далее). ! jpgraph_pie.php – модуль для построения плоских диаграмм. ! jpgraph_pie3d.php – модуль для построения 3D-диаграмм. ! jpgraph_gantt.php – модуль для построения графиков Ганта. ! jpgraph_radar.php, jpgraph_polar.php – модули позволяют строить «центростремительную графику». ! jpgraph_regstat.php – модуль для построения сглаженных графиков. ! jpgraph_scatter.php – модуль для отображения распределенных по плоскости элементов и векторов. ! jpgraph_iconplot.php – модуль для работы с иконками, которые могут быть добавлены к графикам. ! jpgraph_plotband.php – модуль для работы с группами данных на графиках. ! jpgraph_canvas.php – модуль для возможности построения произвольных графиков. ! jpgraph_canvtools.php – модуль для возможности построения произвольных форм. С полным списком подключаемых модулей вы можете ознакомиться в соответствующем разделе документации. В коммерческую версию библиотеки входят ещё несколько модулей, а именно: ! jpgraph_windrose.php – модуль для построения розы ветров. ! jpgraph_odo.php – модуль для отображения одометрических данных. ! jpgraph_barcode.php – модуль для построения линейных штрих-кодов. ! jpgraph_pdf417.php – модуль для построения штрих-кодов PDF417 2D.
Усложняем задачу Теперь, используя полученную информацию, посмотрим, на что ещё способна библиотека JpGraph.
web Сглаженный график
Результат:
В вышеприведенном примере необходимость сглаживать линии графика отсутствует, но для того, чтобы просто продемонстрировать эту возможность, мы сделаем это, немного расширив диапазон значений. Сначала представим исходные данные: $traff = array(810,480, 550, 715, 688, 785, 847,902, 350, ↵ 280, 450, 615, 588,755, 547,320, 380); // òðàôèê (Ìá) $days = array (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ↵ 13, 14, 15, 16, 17); // äàòû
Теперь строим сглаженный график, подключив для этого ещё один модуль: include "../jpgraph.php"; include "../jpgraph_line.php"; include "../jpgraph_regstat.php"; $spline = new Spline($days,$traff); list($newx,$newy) = $spline->Get(100); $g = new Graph(300,200); $g->SetMargin(30,20,40,30); $g->SetScale('linlin'); $g->xaxis->SetLabelFormat('%0.0f'); $lplot = new LinePlot($newy,$newx); $g->Add($lplot); $g->Stroke();
Общая схема та же, что и в случае с простым графиком, но в данном случае мы создаём объект Spline(), описанный в модуле jpgraph_regstat.php. Быть может, результат не очень впечатляет, но довести его до приличного вида большого труда не составит.
Ðèñóíîê 5
Бары (гистограммы) Указанное в заголовке представление данных было бы как раз наиболее уместным в предыдущем случае, но мы, следуя наказам менеджмента, используем эту визуализацию несколько для другого – для отображения количества подключённых клиентов. Опять берём два массива: $pepl = array(8, 16, 10, 7, 4,12, 7,15, 11, ↵ 22); // êîëè÷åñòâî ïîäêëþ÷åíèé $days = array (9, 10, 11, 12, 13, 14, 15, 16, 17, 18); // äàòû
И строим простую гистограмму: $width=480; $height=280; $graph = new Graph($width,$height,'auto'); $graph->SetScale("textlin"); $graph->SetBox(); $graph->xaxis->SetTickLabels($days); $bplot = new BarPlot($pepl); $bplot->SetWidth(0.5); $graph->Add($bplot); $graph->Stroke();
Собственно, это и всё. Немногим отличается от предыдущих примеров. Всего несколько строк кода, а результат уже почти годен к употреблению. Сделаем его пригодным окончательно.
Ðèñóíîê 4
Добавим на график маркеры, соответствующие точным значениям трафика, и нарисуем координатную сетку. Сначала подключим ещё один модуль: include "../jpgraph_scatter.php";
Теперь расставляем маркеры: $splot = new ScatterPlot($traff, $days); $splot->mark->SetFillColor('blue@0.3'); $splot->mark->SetColor('green@0.5'); $g->Add($splot);
Ðèñóíîê 6
Сначала добавим подписи к столбцам и заголовки: И координатную сетку: $g->xgrid->Show();
№1, январь 2005
$graph->title->SetFont(FF_VERDANA,FS_BOLD,11); $graph->title->Set("Ïîäêëþ÷åíèÿ"); $graph->subtitle->SetFont(FF_VERDANA,FS_NORMAL,9);
73
web $graph->subtitle->Set("(Äåêàáðü 2004)"); $bplot->value->Show(); $bplot->value->SetFont(FF_ARIAL,FS_BOLD,8); $bplot->value->SetAlign('left','center'); $bplot->value->SetColor("white"); $bplot->value->SetFormat('%.0f'); $bplot->SetValuePos('max');
Теперь сделаем картинку немножко привлекательней: $graph->SetMarginColor('white'); $graph->SetBackgroundGradient('white','lightblue', ↵ GRAD_HOR,BGRAD_PLOT); $graph->SetFrame(false); $graph->xaxis->SetFont(FF_VERDANA,FS_NORMAL,8); $graph->xaxis->SetLabelMargin(10); $graph->xaxis->SetLabelAlign('right','center'); $graph->yaxis->scale->SetGrace(20); $bplot->SetShadow(); $bplot->SetFillGradient('green','blue',GRAD_HOR);
$graph->title->SetFont(FF FF_VERDANA,FS_BOLD,8); $graph->title->Set("Ðàñïðåäåëåíèå òðàôèêà"); $graph->legend->SetColor('navy'); $graph->legend->SetFillColor('lightgreen'); $graph->legend->SetLineWeight(1); $graph->legend->SetFont(FF_ARIAL,FS_NORMAL,8); $graph->legend->SetShadow('gray@0.4',3); $graph->legend->SetAbsPos(10,100,'right','bottom'); $legends = array('Ôèç ëèöà','Þð Ëèöà','Ñëóæåáíûé'); $p1->SetLegends($legends);
Результат вполне информативен (рис. 9), но, как и в предыдущих примерах, для красоты придадим диаграмме объем и выделим служебный трафик.
Я не думаю, что данный код требует каких-либо объяснений. Всё вполне интуитивно понятно. Результат, конечно не является шедевром делового дизайна, но вполне приемлем.
Ðèñóíîê 8
Ðèñóíîê 7
Диаграммы Для демонстрации этой возможности также не будем далеко уходить от реальности. Пусть на круговой диаграмме необходимо отобразить распределение потребляемого трафика. Допустим, что трафик, израсходованный физическими лицами за текущий месяц, составил 54.36 Гб, юридическими – 64.57 Гб, и, наконец, 6.75 Гб ушли на внутренние нужды провайдера. Следующими несколькими строчками кода (обратившись к расширению PieGraph) рисуем простую круговую диаграмму: <? include ("../jpgraph.php"); include ("../jpgraph_pie.php"); $data = array(54.36, 64.57, 6.75); $graph = new PieGraph(300,200); $p1 = new PiePlot($data); $graph->Add($p1); $graph->Stroke(); ?
Результат показан на рис. 8. Как видите, проценты реализации библиотека вычисляет сама (мелочь, а приятно). Добавляем заголовок и для пояснения создаем легенду (пояснения к диаграмме или карте, иначе говоря «условные обозначения»). Легенду можно добавить практически ко всем объектам JpGraph, она представляет собой самостоятельный объект:
74
Ðèñóíîê 9
Нужно заметить, что для работы следующего кода необходима вторая версия библиотеки GD, но так как в дистрибутив PHP в настоящее время входит расширение GD2, это обстоятельство проблем создать не должно. Для начала подключаем ещё один модуль: include ("../jpgraph_pie3d.php");
Заменяем вид диаграммы: //$p1 = new PiePlot($data); $p1 = new PiePlot3D($data);
Выделяем служебный трафик: $p1->ExplodeSlice(2);
Изменяем цвета по умолчанию:
web $p1->SetSliceColors(array('skyblue3','yellow3','darkred'));
Наконец, убираем совершенно неуместную в данном случае рамку: $graph->SetFrame(false);
Полученный результат, думается, годится для представления.
тега <img>. Если бы не этот механизм, в случае возникновения вышеописанной ошибки в браузер выводилось бы не привычное для разработчика сообщение, а рамка отсутствующего рисунка, которая, разумеется, жизнь программисту никак не облегчает. Более того, при работе с библиотекой имеет смысл писать свои обработчики ошибок с графическим выводом (благо её возможности это вполне позволяют) к таким распространённым сбоям, как неудачный запрос к базе данных или неполадки при работе с файловой системой.
Ðèñóíîê 11
Что в перспективе
Ðèñóíîê 10
Дополнительные возможности Кэширование Любой программист, работавший с библиотекой GD, знает, как сильно генерация изображений потребляет системные ресурсы. Если подобный график требуется создавать раз в сутки – ничего страшного, но если в вашем офисе десяткам менеджеров требуются эти данные ежеминутно, создание графиков на лету порождает серьёзные проблемы с производительностью. Поэтому нельзя переоценить ещё одну впечатляющую возможность JpGraph – управляемое кэширование изображений. Под этим термином здесь подразумевается сохранение созданного изображения на сервере, на заранее заданный период времени. В самом деле, данные по ежедневному трафику обновляются раз в сутки, соответственно более одного раза за 24 часа создавать изображение не имеет смысла. Для этого в объявлении нового класса указываем (кроме размеров графа) имя файла, в котором будет сохранено изображение, и период актуальности данного кэша в минутах: $graph = new Graph(450, 200, "traf”, 1464, true);
Теперь при повторном запросе графика в течение 24 часов клиенту будет возвращено сохранённое в файле изображение, а выполнение скрипта прервется.
Сообщения об ошибках Если при обращении к какому-либо объекту или методу библиотеки была допущена ошибка, в браузер вместо изображения отправляется графическое сообщение об ошибке, аналогичное показанному на рис. 10. Для чего это нужно? Всё просто. Основной способ передачи изображений, созданных JpGraph, – использование
№1, январь 2005
Библиотека JpGraph живёт и развивается, обрастая новыми модулями. Неожиданное препятствие на пути её использования возникло в связи с переходом разработчиков на пятую версию языка PHP с совершенно другой объектной моделью. Это общая проблема любых ОО-библиотек, заточенных под PHP 4. Язык обрёл новые возможности, но, как это нередко бывает, потерял частично обратную совместимость. Так, уже первый пример из скрипта tessuit.php на новом движке выдаёт ошибку. Что делать? Можно, конечно, подправить код библиотеки (причём, скорее всего, отказавшись от некоторых возможностей), но можно и немного подождать. Создатели JpGraph держат руку на пульсе прогресса, и уже доступна альфа-версия библиотеки JpGraph 2, ориентированная на пятую версию PHP (вернее, на новую объектную модель). Мне кажется, что внесенные изменения не будут препятствовать разработчикам, а напротив, помогут освоить новые горизонты.
Заключение Конечно, в этой статье я осветил лишь небольшую часть возможностей JpGraph. За кадром остались использование карт-изображений (image-map), генерация текста, работа с готовой графикой, с фоновыми изображениями и многое другое. Изучить их несложно. Как уже упоминалось, JpGraph – не единственное средство для работы с графикой на PHP. Широко распространены такие инструменты, как мощнейший по возможностям, но, к сожалению, коммерческий пакет для работы с деловой графикой ChartDirector, или библиотека по работе с готовыми изображениями ImageMagic. Наличие таких средств обработки графики, конечно, ещё не повод исключить из процесса «сайтостроительства» дизайнера, но возможность иногда обойтись кодом без участия дорогостоящих графических пакетов весьма приятна. При написании данного материала были использованы статья Александра Шиляева «JpGraph и русский язык» (http://detail.phpclub.ru/article/jpgraph_ru) и перевод руководства по Jpgraph, выполненный Екатериной Жемойтук.
75
bugtraq Удаленный отказ в обслуживании в службах ITS, CME и SRST на Cisco IOS
Выполнение произвольного кода в HP-UX ftpd debug logging
Программа: Cisco IOS 12.1YD, 12.2T, 12.3 и 12.3T. Опасность: Высокая. Описание: Обнаружен отказ в обслуживании в Cisco IOS, сконфигурированной с поддержкой Telephony Service (ITS), Cisco CallManager Express (CME) или Survivable Remote Site Telephony (SRST). ITS, CME и SRST являются службами, которые позволяют контролировать IP-телефоны с помощью протокола SCCP (Skinny Call Control Protocol). Удаленный пользователь может послать специально сформированные пакеты на SCCP-порт (2000) устройства и вызвать его перезагрузку. Большое количество таких пакетов приведет к отказу в обслуживании системы. URL производителя: http://cisco.com. Решение: Установите обновления с сайта производителя.
Программа: HP-UX 11.00, 11.04, 11.11, 11.22. Опасность: Высокая. Описание: Обнаружено переполнение буфера в HP-UX ftpd. Удаленный атакующий может выполнить произвольный код на уязвимой системе. Уязвимость существует, если ftpd-демон сконфигурирован посредством /etc/inetd.conf и ведет лог отладки с параметром v (конфигурация по умолчанию). Удаленный атакующий может послать демону специально сформированную команду, вызвать переполнение стека и выполнить произвольный код на уязвимой системе с привилегиями ftpd-процесса. Для эксплуатации этой уязвимости не требуется авторизация на сервере. URL производителя: http://www.hp.com. Решение: Установите патчи с сайта производителя.
Выполнение произвольных команд в PHProjekt Программа: PHProjekt 4.2.2. Опасность: Высокая. Описание: Обнаружена уязвимость в PHProjekt. Удаленный атакующий может выполнить произвольные команды на уязвимой системе. Уязвимость существует в сценарии authform.inc.php. Удаленный атакующий может изменить значение глобальной переменной $path_pre на внешний URL и выполнить произвольный php-сценарий на системе с привилегиями севера. URL производителя: www.phprojekt.com. Решение: Установите обновление: http://www.phprojekt.com/ files/4.2/lib.zip.
Выполнение произвольного кода Netscape Directory Server на HP-UX Программа: HP-UX B.11.00, B.11.11, B.11.23 Опасность: Критическая. Описание: Обнаружена уязвимость в Netscape Directory Server на HP-UX при использовании LDAP. Удаленный пользователь может выполнить произвольный код на уязвимой системе. Уязвимость существует из-за переполнения буфера в Netscape Directory Server. Злоумышленник может вызвать отказ в обслуживании или выполнить произвольный код на уязвимой системе. Решение: Установите исправления с сайта производителя.
Несколько уязвимостей в Sybase Adaptive Server Enterprise Программа: Sybase Adaptive Server Enterprise 12.5.2 и более ранние версии. Опасность: Критическая. Описание: Обнаружено три критических уязвимости в Sybase Adaptive Server Enterprise. Подробности не сообщаются. URL производителя: http://www.sybase.com/products/data baseservers/ase. Решение: Установите исправление: http://www.sybase.com/ products/informationmanagement/adaptiveserverenterprise.
76
Отказ в обслуживании в MaxDB Web Agent Программа: MySQL MaxDB Web Agent версии до 7.5.0.21, SAP DB Web Agent. Опасность: Высокая. Описание: Две уязвимости в MySQL MaxDB Web Agent и SAP DB Web Agent позволяют удаленному пользователю вызвать отказ в обслуживании. Уязвимость существует в функции sapdbwa_GetUserData(). Удаленный пользователь может вызвать код обработчика webdav с некорректным параметром и вызвать отказ в обслуживании приложения. Уязвимость существует из-за недостаточной фильтрации данных в HTTP-заголовках. Удаленный пользователь может с помощью специально сформированных HTTP-заголовков вызвать отказ в обслуживании приложения. URL производителя: http://www.mysql.com/products/maxdb. Решение: Установите обновление: http://dev.mysql.com/ downloads/maxdb/7.5.00.html.
Выполнение произвольного кода в Kerberos 5 в библиотеке libkadm5srv Программа: krb5-1.3.5 и более ранние версии. Опасность: Высокая. Описание: Обнаружено переполнение буфера в Kerberos 5 в административной библиотеке libkadm5srv при обработке истории паролей. Удаленный пользователь может выполнить произвольный код на уязвимом KDC-хосте. Уязвимость обнаружена в функции add_to_history() файла src/lib/kadm5/srv/svr_principal.c. При определенной политике безопасности паролей злоумышленник может выполнить произвольный код на KDC (Key Distribution Center)-хосте. URL производителя: http://web.mit.edu/kerberos/advisories/ MITKRB5-SA-2004-004-pwhist.txt Решение: Установите патч: http://www.mozilla.org/products/ mozilla1.x и http://web.mit.edu/kerberos/advisories/2004-004patch_1.3.5.txt.
Составил Александр Антипов
на правах рекламы
ВЕБ-СЕРВИС ДЛЯ РАЗРАБОТЧИКОВ САЙТОВ ДАНИИЛ АЛИЕВСКИЙ Один из важнейших классов инструментов, используемых при создании сайтов, – так называемые веб-сервисы, позволяющие дополнить сайт новыми функциями. Общеизвестный пример – счетчики, например, популярные в России www.spylog.ru или www.hotlog.ru. Вы регистрируетесь, копируете на свои страницы фрагмент HTML-кода и получаете доступ к подробным статистическим отчетам о посещаемости сайта. Другой пример – сервисы, предоставляемые известными поисковыми системами, такими как Google или Yandex. С их помощью вы можете создать форму для поиска информации на вашем сайте. Веб-сервисы обладают целым рядом важных достоинств. Во-первых, использовать их чрезвычайно просто: все сводится к копированию и вставке некоторого HTML-кода в текст вашей страницы. Эта операция доступна любому «чайнику». Во-вторых, авторы сервисов постоянно совершенствуют свои продукты, и это автоматически отражается на вашем сайте. В-третьих, веб-сервисы не зависят от хостинга: если вы решите перенести сайт в другое место, достаточно будет просто скопировать все страницы. Список преимуществ можно продолжить. К сожалению, на сегодня число веб-сервисов для разработчиков сайтов весьма ограниченно. Кроме счетчиков и поисковиков, можно назвать системы перевода на другие языки, такие как www.translate.ru. Но подобные решения пока не завоевали популярности среди авторов сайтов. Хотя, казалось бы, что может быть логичнее: добавить для иностранных посетителей кнопочку «перевести мой сайт на такой-то язык». Конечно, перевод будет «корявым». Но иногда это лучше, чем его полное отсутствие. WebWarper – новый многофункциональный веб-сервис, изначально рассчитанный на улучшение сайтов. Это фильтр, «пропускающий» сайты через себя. Пройдя через него, сайт обретает новые возможности. Пожалуй, самая оригинальная из них – антивирусная защита. Множество людей заражаются вирусами через обычные веб-страницы, легкомысленно согласившись инсталлировать какой-нибудь модуль ActiveX. WebWarper удаляет опасный код со всех просматриваемых страниц. Спрашивается: зачем защищать посетителя на моем собственном сайте, на котором никаких вирусов нет? И правда незачем, если сайт столь незатейлив, что на нем нет ни рекламы, ни ссылок на внешние ресурсы. Если же есть – кто поручится, что посетители, уйдя по ссылке на чужой сайт или, скажем, увидев рекламу с баннерной сети, не подцепят какой-нибудь троян или вирус? А как вы думаете, кого они в этом обвинят? Очень вероятно, что вас – особенно если заражение произошло через рекламу или вскоре после ухода с вашей страницы.
№1, январь 2005
WebWarper позволяет подстраховаться. Если предложить посетителю смотреть сайт «сквозь» WebWarper, то и чужие сайты, на которые он перейдет по вашим ссылкам, с высокой вероятностью окажутся «очищенными» от вирусов. Не менее ценным может оказаться сжатие данных. Страницы, «пропущенные» через WebWarper, незаметно для пользователя сжимаются в полтора-три раза (нечто вроде известного zip). Сейчас все больше людей переключается с модемов на кабельные сети с помегабайтной оплатой трафика. В России, увы, цены пока не настолько низкие, чтобы объемом трафика можно было пренебречь. При активной работе в Интернете за месяц можно запросто израсходовать от нескольких сотен до нескольких тысяч рублей. Если на вашем сайте посетитель потратит вдвое меньше трафика, он это оценит. Еще один нюанс. Если у посетителя очень медленный или перегруженный канал – скажем, в каком-нибудь курортном интернет-кафе – некоторые сайты грузятся невыносимо медленно. Благодаря сжатию доступ через WebWarper может оказаться более эффективным (хотя возможна и обратная ситуация). Далее, WebWarper является анонимайзером. Не каждому сайту нужна анонимность его посетителей. Но бывают случаи, когда уместно предложить пользователям смотреть ваши страницы и сайты, на которые у вас есть ссылки, анонимно, не «засвечивая» свой настоящий IP. В конце концов, приватность – изначальное право посетителя. Кроме улучшения сайта, WebWarper предлагает обмен ссылками: сайты, использующие его для оптимизации, попадают в список на webwarper.net. Это неплохой способ продвижения ресурса, учитывая популярность сервиса. (В открытой статистике рейтинга SpyLOG на сегодня приведены такие данные: ~6000 посетителей в день, 4,5 млн. посетителей за всю историю, 5-е место в группе «Бесплатные интернетсервисы».) Главная русскоязычная страница проекта: http:// webwarper.net/wwr. Возможности, аналогичные перечисленным, обеспечивают также некоторые другие инструменты. Прежде всего нужно сказать про mod_gzip: бесплатный модуль к веб-серверу Apache. Если на сервере инсталлирован mod_gzip, то все веб-страницы автоматически сжимаются тем же методом, что и в случае WebWarper. Это решение – для профессионалов, хорошо ориентирующихся в UNIX и имеющих достаточные права для установки модулей Apache. (Возможно, в будущем большинство хостингкомпаний станут инсталлировать mog_gzip изначально: тогда эта возможность станет доступна «чайникам».) Что касается антивирусной защиты WebWarper, то аналогичная фильтрация может поддерживаться коммерческими брандмауэрами, установленными между вашим сервером и внешним миром. Также существуют веб-сервисы, специализирующиеся на анонимайзинге: например, http:// anonymouse.ws.
77
hardware
ЗАПИСЬ ДИСКОВ CD-R/RW В LINUX ЧАСТЬ 3
ВЛАДИМИР МЕШКОВ В третьей части статьи рассматривается порядок использования мультимедийных команд стандарта SCSI (SCSI MultiMedia Commands) для записи многосессионных CD-R/RW дисков в режиме TAO (Track-at-Once). Работоспособность всех примеров программ была проверена для ОС Linux, ядро 2.4.28. В ядре включены режим SCSI-эмуляции для ATAPI-устройств (SCSI host adapter emulation for IDE ATAPI devices) и поддержка SCSI Generic драйвера. Использовались следующие модели приводов для чтения и записи CD-R/RW и DVD-R/RW дисков: ! TEAC CD-W524E 1.0E ! MITSUMI CR-48XATE ! _NEC CD-RW NR-9400A R800 ! ASUS DRW-1604P 1.09
Работа над ошибками Прежде чем приступить к рассмотрению основного материала, устраним ошибки, допущенные во второй части статьи [5]. Проблема заключается в следующем – при попытке записи информации с использованием привода ASUS программа аварийно завершает выполнение со следующим сообщением: lba - 320 Sense data: 0x70 0x00 0x02 0x00 0x00 0x00 0x00 0x0e 0x00 0x00 0x00 0x00 0x04 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 Driver status=0x28 Cannot write image.iso
Здесь Sense Key = 0x02, ASC = 0x04, ASCQ = 0x08, что означает LOGICAL UNIT NOT READY, LONG WRITE IN PROGRESS (устройство не готово к работе, выполняется операция длинной записи). Остановка выполнения программы всегда происходит на секторе номер 320. Аналогичным образом ведут себя приводы MITSUMI и _NEC. С приводом TEAC подобной проблемы не возникало. В чем причина этой ошибки? Дело в том, что каждый привод имеет внутренний буфер для данных, и при записи информация сначала попадает в этот буфер, а затем из него переносится на диск. Буфер имеет ограниченную ёмкость, определить которую можно при помощи команды READ BUFFER CAPACITY. Формат этой команды приведён на рис.1.
Ðèñóíîê 2. Ôîðìàò áëîêà äàííûõ î áóôåðå óñòðîéñòâà, BLOCK = 0
Здесь Length of the Buffer – размер буфера в байтах, Available Length of Buffer – размер неиспользуемой (доступной) области буфера в байтах. Модифицируем листинг из второй части – при записи информации будем контролировать размер доступной области внутреннего буфера устройства при помощи функции read_buff_cap(): __u32 read_buff_cap() { __u8 read_buff_cap_cmd[10]; __u8 data_buff[12]; __u32 buff_alen = 0; memset(read_buff_cap_cmd, 0, 10); read_buff_cap_cmd[0] = 0x5C; read_buff_cap_cmd[8] = 0x0C; send_cmd(read_buff_cap_cmd, 10, SG_DXFER_FROM_DEV, ↵ data_buff,0x0C, 20); memcpy((void *)&buff_alen, data_buff + 8, 4); buff_alen = __swab32(buff_alen);
}
printf("\tAvailable length - %u\n", buff_alen); return buff_alen;
Контроль за размером доступной области буфера будет выполняться в функции write_iso, в цикле записи информации (полный листинг этой функции находится в [5]): int write_iso(__u8 *file_name) { .... while(read(in_f, write_buff, CD_FRAMESIZE) > 0) { read_buff_cap(); printf("lba - %6d", lba1); lba = __swab32(lba1); memcpy((write_cmd + 2), (void *)&lba, 4); lba1 += 1; send_cmd(write_cmd, 10, SG_DXFER_TO_DEV, ↵ write_buff, CD_FRAMESIZE, 20);
Ðèñóíîê 1. Ôîðìàò êîìàíäû READ BUFFER CAPACITY
Если поле BLOCK установлено в 0, устройство вернёт блок данных следующего формата (рис.2):
78
}
} return 0;
Результат работы программы (привод ASUS):
hardware Available length - 1267712 lba 0 Available length - 1175552 lba 1 Available length - 1173504 lba 2 Available length - 1171456 ........ lba 317 Available length - 526336 lba 318 Available length - 524288 lba 319 Available length - 0 lba - 320 Sense data: 0x70 0x00 0x02 0x00 0x00 0x00 0x00 0x0e 0x00 0x00 0x00 0x00 0x04 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 Driver status=0x28 Cannot write image.iso
int send_cmd(__u8 *cmd, __u8 cmdlen, int direction, ↵ __u8 *data, __u32 datalen, unsigned int timeout) { sg_io_hdr_t io_hdr; __u8 sense_buffer[32]; #define SK sense_buffer[2] #define ASC sense_buffer[12] #define ASCQ sense_buffer[13] memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = cmdlen; io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = direction; io_hdr.dxfer_len = datalen; // ðàçìåð äàííûõ io_hdr.dxferp = data; // óêàçàòåëü íà áëîê äàííûõ io_hdr.cmdp = cmd; io_hdr.sbp = sense_buffer; io_hdr.timeout = timeout * 1000;
Как только доступная область буфера становится равной нулю, устройство на попытку передачи ему информации отвечает LOGICAL UNIT NOT READY, LONG WRITE IN PROGRESS. Один из вариантов решения данной проблемы – подождать, пока буфер устройства освободится, а затем продолжить запись, например:
if(ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("SG_IO ioctl"); return -1; }
while(read_buff_cap() == 0) continue;
Такой вариант устраивает ASUS, но MITSUMI и _NEC так просто не сдаются и, попав в цикл, не хотят его покидать. Спецификация SFF8090i [1] при возникновении такого рода ошибки требует повторить команду записи (см. п.14.48 WRITE(10) command): While writing is occurring, if WRITE (10) command or WRITE (12) command cannot be terminated immediately due to insufficient buffer capacity, the logical unit may terminate the WRITE command with CHECK CONDITION status, 2/04/08 LOGICAL UNIT NOT READY, LONG WRITE IN PROGRESS and the host shall issue the same WRITE command again. After logical unit becomes ready due to sufficient buffer capacity for the WRITE command, the WRITE command shall be performed normally.
if((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) { if(io_hdr.sb_len_wr > 0) { /* Åñëè SK/ASC/ASCQ == 02/04/08 (Not Ready. Long Write * in Progress), òî íåîáõîäèìî ïîâòîðèòü êîìàíäó WRITE_10 */ if((SK == NOT_READY) && (ASC == 0x04) && ↵ (ASCQ == 0x08)) return 1; syslog(LOG_INFO,"Command: 0x%02X", io_hdr.cmdp[0]); syslog(LOG_INFO,"Sense data (SK/ASC/ASCQ): ↵ 0x%02X/0x%02X/0x%02X",SK,ASC,ASCQ); }
Именно таким образом поступает dvdrecord. Запустив его с ключом -v, мы увидим следующую картину: Executing 'write_g1' command on Bus 0 Target 1, Lun 0 timeout 200s CDB: 2A 00 00 00 3A 01 00 00 1F 00 dvdrecord: Input/Output error, write_g1: scsi sendcmd: no error CDB: 2A 00 00 00 3A 01 00 00 1F 00 Status: 0x2 (CHECK CONDITION) Sense buffer: 70 00 02 00 00 00 00 0E 00 00 00 00 04 08 00 00 Sense Key: 0x2 Not Ready, Segment 0 Sense Code: 0x04 Qual 0x08 (logical unit not ready, Long write in progress) Fru 0x0 Sense flags: BLK 0 (not valid) cmd finished after 0x000 s timeout 200s Executing 'write_g1' command on Bus 0 Target 1, Lun 0 timeout 200s CDB: 2A 00 00 00 3A 01 00 00 1F 00 cmd finished after 0x000 s timeout 200s
CDB – это Command Descriptor Block (дескриптор командного блока), 2A – код команды WRITE_10. Зафиксировав ошибку LONG WRITE IN PROGRESS, программа dvdrecord в соответствии с требованием спецификации повторно посылает устройству команду записи. Исходя из вышеизложенного, внесём исправления в текст программы для записи ISO-образа на CD-R/RW диск. Изменениям подвергнутся функция посылки пакетной команды устройству send_cmd() и функция записи write_iso:
№1, январь 2005
}
if(io_hdr.masked_status) syslog(LOG_INFO, "SCSI status = 0x%x\n", ↵ io_hdr.status); if(io_hdr.host_status) syslog(LOG_INFO, "Host status = 0x%x\n", ↵ io_hdr.host_status); if(io_hdr.driver_status) syslog(LOG_INFO, "Driver status = 0x%x\n", ↵ io_hdr.driver_status); return -1; } return 0;
Текст функции write_iso() целиком приводить не будем, рассмотрим только ключевой фрагмент – посылку устройству командного пакета: while(1) { ret = send_cmd(write_cmd, 10, SG_DXFER_TO_DEV, ↵ write_buff, BUFF_SIZE, 20); if(ret == 1) continue; // LONG WRITE IN PROGRESS if(ret == 0) break; if(ret < 0) return -1; // îøèáêà çàïèñè! }
Команда WRITE_10 будет посылаться устройству до тех пор, пока не будет успешно выполнена или не произойдет ошибка, отличная от SK/ASC/ASCQ = 02/04/08 «NOT READY. LONG WRITE IN PROGRESS». Исходный текст утилиты, выполняющей запись данных на CD-R/RW диск находится по адресу http://bob.netport.com. ua/iso2сd.tar.gz. На этом закончим изучение односессионных CD-дисков и рассмотрим, что нужно сделать для того, чтобы создать многосессионный диск.
Запись многосессионного диска Для создания многосессионного диска необходимо присвоить полю Multi-session страницы параметров режима записи
79
hardware значение 11b (см. [1, 2]). В этом случае при формировании Lead-In-области указатель B0 таблицы содержания диска (Table of Contents, TOC) будет содержать координаты начала следующей области программ (формат TOC и пример чтения были рассмотрены в [3]). Формирование образа, который будет записан первым, ничем не отличается от формирования образа для односессионного диска. Каждый новый записываемый образ должен содержать ссылку на предыдущий, чтобы драйвер файловой системы мог собрать содержимое всех сессий в единое целое. Для этого при формировании ISOобраза (кроме первого) в опциях утилиты mkisofs необходимо указать стартовые координаты первого трека последней сессии и координаты следующей возможной области программ. Назовем эти координаты A и B. При помощи cdrecord значения A и B определяются следующим образом:
/* ×èñëî çàïèñåé TOC */ toc_entries = (toc_data_len - 2)/11; /* ×èñëî ñåññèé */ last = data_buff[3]; printf("×èñëî ñåññèé íà äèñêå - %d\n", last); t = (toc_t *)malloc(toc_data_len); memset((void *)t, 0, toc_data_len); memcpy((void *)t, data_buff + 4, toc_data_len); free(data_buff); printf("Entry\tSession\tPoint\tMin\tSec\tFrame\ ↵ tPMin\tPsec\tPFrame\tLBA\n"); for(i = 0; i < toc_entries; i++) { printf("%d\t", i); printf("%d\t", (t + i)->snum); printf("%X\t", (t + i)->point); printf("%d\t", (t + i)->min); printf("%d\t", (t + i)->sec); printf("%d\t", (t + i)->frame); printf("%d\t", (t + i)->pmin); printf("%d\t", (t + i)->psec); printf("%d\t", (t + i)->pframe);
cdrecord -dev=X,Y,Z -msinfo
где X, Y и Z – это координаты устройства (msinfo – это сокращение от multi-session information). После выполнения команды мы получим два числа – искомые стартовые координаты. Эти числа необходимо указать в соответствующих опциях mkisofs (опция -C, см. man mkisofs) при подготовке образа для записи. Рассмотрим два способа определения значений A и B. Оба способа подразумевают чтение таблицы содержания диска (TOC), только в первом случае мы читаем «сырую» таблицу (RAW TOC), в во втором – информацию о сессиях. При помощи функции read_raw_toc() прочитаем RAW TOC: /* Ôîðìàò çàïèñè TOC (ñì. [1, 2]) */ typedef struct { __u8 snum; // Session Number __u8 ctrl :4; // Control __u8 adr :4; // ADR __u8 tno; // TNO (always 0) __u8 point; // POINT __u8 min; // AMIN __u8 sec; // ASEC __u8 frame; // AFRAME __u8 zero; // 0 __u8 pmin; // PMIN __u8 psec; // PSEC __u8 pframe; // PFRAME } toc_t; int read_raw_toc() { int i; __u8 read_toc_cmd[10]; __u8 *data_buff; // ðåçóëüòàòû ÷òåíèÿ TOC __u16 toc_data_len = 0; // äëèíà çàïèñåé TOC __u32 lba; int toc_entries = 0; // ÷èñëî çàïèñåé TOC int last = 0; // íîìåð ïîñëåäíåé ñåññèè toc_t *t;
#define #define #define #define #define #define #define
PMIN(i) (t + i)->pmin PSEC(i) (t + i)->psec PFRAME(i) (t + i)->pframe MIN(i) (t + i)->min SEC(i) (t + i)->sec FRAME(i) (t + i)->frame POINT(i) (t + i)->point
if((POINT(i) == 0xC0) || (POINT(i) == 0xC1)) { printf("\n"); continue; } /* Êîîðäèíàòû íà÷àëà ñëåäóþùåé âîçìîæíîé îáëàñòè ïðîãðàìì * ñîäåðæèò óêàçàòåëü B0 â ïîëÿõ Min/Sec/Frame. Ïåðåâîäèì * ýòè êîîðäèíàòû â LBA-ôîðìàò, ñ ó÷åòîì òîãî, ÷òî ïåðåä * òðåêîì íàõîäèòñÿ Pre-gap îáëàñòü ðàçìåðîì 150 ñåêòîðîâ */ if(POINT(i) == 0xB0) lba = MSF2LBA(MIN(i), SEC(i), ↵ FRAME(i)) + 150; else lba = MSF2LBA(PMIN(i), PSEC(i), PFRAME(i)); printf("%u\n", lba); }
}
free(t); return 0;
Пересчёт координат из MSF-формата в LBA выполняет макрос MSF2LBA следующего вида: #define MSF2LBA(Min, Sec, Frame) (((Min * 60 + Sec) * 75 + ↵ Frame) - 150)
Теперь возьмём диск, на котором записано три сессии, и посмотрим на результат работы функции read_raw_toc():
data_buff = (__u8 *)malloc(0xFFFF); memset(data_buff, 0, 0xFFFF); memset(read_toc_cmd, 0, 10); read_toc_cmd[0] read_toc_cmd[2] read_toc_cmd[7] read_toc_cmd[8]
= = = =
READ_TOC; 2; // Format Field = 10b - RAW TOC 0xFF; 0xFF;
send_cmd(read_toc_cmd, 10, SG_DXFER_FROM_DEV, ↵ data_buff, 0xFFFF, 20); /* Ðàçìåð TOC */ *((__u8 *)&toc_data_len) = data_buff[1]; *((__u8 *)&toc_data_len + 1) = data_buff[0];
80
Указатель A0 третьей сессии (запись 12) содержит в поле PMin номер первого трека последней сессии. Это значение равно 3. Запись 15 в полях PMin/PSec/PFrame содержит
hardware стартовые координаты этого трека – 5/15/35, или 23510 в LBA-формате. Координаты начала следующей возможной области программ содержит указатель B0 в полях Min/Sec/ Frame (запись 16) – 7/13/59 (32534 в LBA-формате). Второй способ определения значения числа A – чтение информации о сессиях. Для этого в поле Format командного блока READ TOC/PMA/ATIP (см. спецификацию [2], табл. 441) должно принять значение 1. Блок информации о сессиях имеет вид, представленный на рис. 3.
Осталось узнать значение числа B – стартового адреса следующей возможной области программ. Этот адрес является адресом невидимого трека (invisible track), и определить его можно при помощи команды READ TRACK INFORMATION. Формат этой команды и пример использования был рассмотрен в [5]. Следующая функция выполняет чтение искомого адреса: __u32 read_track_info(int trk_num) { __u8 read_track_info_cmd[10]; __u8 data_buff[40]; __u32 lba = 0; memset(data_buff, 0, 40); memset(read_track_info_cmd, 0, 10); read_track_info_cmd[0] = 0x52; read_track_info_cmd[1] = 1; read_track_info_cmd[5] = trk_num; // 0xFF - ↵ invisible track read_track_info_cmd[8] = 40; send_cmd(read_track_info_cmd, 10, ↵ SG_DXFER_FROM_DEV, data_buff, 40, 20);
} Ðèñóíîê 3. Áëîê èíôîðìàöèè î ñåññèÿõ
Здесь First и Last Complete Session Number – номера первой и последней завершенной сессии, First Track Number In Last Complete Session – номер первого трека в последней завершенной сессии, Start Address of First Track in Last Session – стартовый адрес этого трека. Формат блока информации о сессиях описывает следующая структура: typedef struct { __u8 res1; __u8 ctrl :4; __u8 adr :4; __u8 first_trk; // íîìåð ïåðâîãî òðåêà ïîñëåäíåé ñåññèè __u8 res2; __u32 start_addr; // ñòàðòîâûé àäðåñ òðåêà } ms_info_t;
memcpy((void *)&lba, (void *)(data_buff + 8), 4); return __swab32(lba);
В результате работы двух рассмотренных функций – read_ms_info() и read_track_info() – мы получим для имеющегося в нашем распоряжении трехсессионного диска значения чисел А и В: A = 23510 и B = 32534. Теперь можно сформировать ISO-образ для записи на диск четвертой сессии: mkisofs -R -J -C 23510,32534 -M [èìÿ ôàéëà óñòðîéñòâà] ↵ -o track-04.iso [âõîäíîé ôàéë]
Перед тем как приступить к записи информации, целесообразно выяснить, в каком состоянии находится диск, т.е. можно ли дописать на него новую сессию. Эту информацию можно получить при помощи команды READ DISK INFORMATION. Формат этой команды представлен на рис. 4.
Чтение блока информации о сессиях выполняет функция read_ms_info(): void read_ms_info() { // íîìåð ïåðâîãî òðåêà ïîñëåäíåé ñåññèè int first_trk = 0; __u8 read_toc_cmd[10]; // CDB - Command Descriptor Block __u8 data_buff[12]; __u32 start_addr = 0; // ñòàðòîâûé àäðåñ òðåêà ms_info_t *ms_info; memset(data_buff, 0, 12); ms_info = (void *)(data_buff + 4); /* Ôîðìèðóåì CDB */ memset(read_toc_cmd, 0, 10); read_toc_cmd[0] = READ_TOC; read_toc_cmd[2] = 1; // Format = 1, ↵ Multi-session Information read_toc_cmd[8] = 12; // ðàçìåð áëîêà äàííûõ send_cmd(read_toc_cmd, 10, SG_DXFER_FROM_DEV, ↵ data_buff, 12, 20); first_trk = ms_info->first_trk; start_addr = __swab32(ms_info->start_addr);
}
printf("Ïåðâûé òðåê ïîñëåäíåé ñåññèè - %d\n", ↵ first_trk); printf("Ñòàðòîâûé àäðåñ òðåêà - %u\n", start_addr); return;
№1, январь 2005
Ðèñóíîê 4. Ôîðìàò êîìàíäû READ DISK INFORMATION
Формат данных, возвращаемых устройством по этой команде, представлен на рис. 5. Необходимую нам информацию содержит поле Disk Status. Поле может принимать следующие значения: ! 00b – Empty Disk, диск пустой, не содержит информации; ! 01b – Incomplete Disk, незавершенный диск, на который можно дописывать информацию; ! 10b – Finalized Disk, диск завершен, информацию дописывать нельзя. Поле State of last Session описывает состояние последней сессии на диске. Поле может принимать следующие значения:
81
hardware ! 00b – пустая сессия (Empty Session); ! 01b – незавершенная сессия (Incomplete Session); ! 11b – сессия завершена (Complete Session). Установленный в «1» бит Erasable свидетельствует о том, что в приводе находится диск CD-RW, DVD-RAM, DVDRW или DVD+RW. Назначение остальных полей приведено в спецификации [2], п. 6.27 «READ DISK INFORMATION Command».
return 0;
}
Если диск позволяет выполнить запись новой сессии (disk_status == 1), то алгоритм работы программы следующий: ! при помощи системного вызова stat определяется размер записываемого образа в блоках по 2048 байт (режим Data Mode 1): #include <sys/stat.h> struct stat s; memset((void *)&s, 0, sizeof(struct stat)); /* argv[1] - èìÿ ôàéëà-îáðàçà, ïåðåäàåòñÿ * â êîìàíäíîé ñòðîêå ïðîãðàììû */ if(stat(argv[1], &s)) { perror("stat"); exit(errno); } /* Ðàçìåð ôàéëà-îáðàçà â áëîêàõ */ track_size = s.st_size/CD_FRAMESIZE;
! резервируется место для нового трека (команда RESERVE TRACK), при этом размер трека равен размеру файла-образа в блоках. Формат команды RESERVE TRACK был рассмотрен в [5]: void reserv_track(__u32 track_size) { __u8 reserv_track_cmd[10]; __u32 size = 0; memset(reserv_track_cmd, 0, 10); reserv_track_cmd[0] = 0x53; size = __swab32(track_size); memcpy((void *)(reserv_track_cmd + 5), ↵ (void *)&size, 4);
Ðèóíîê 5. Áëîê èíôîðìàöèè î äèñêå, âîçâðàùàåìûé ïî êîìàíäå READ DISK INFORMATION
Чтение информации о диске выполняет функция read_ disk_info(): int read_disk_info() { __u8 read_disk_info_cmd[10]; __u8 data_buff[34];
! при помощи команды READ TRACK INFORMATION определяется стартовый адрес зарезервированного трека, и начиная с этого адреса на диск выполняется запись данных.
memset(data_buff, 0, 34); memset(read_disk_info_cmd, 0, 10); read_disk_info_cmd[0] = 0x51; read_disk_info_cmd[8] = 34;
Полный текст программы для записи многосессионных дисков находится по адресу: http://bob.netport.com.ua/iso2cd_ multi.tar.gz.
send_cmd(read_disk_info_cmd, 10, SG_DXFER_FROM_DEV, ↵ data_buff, sizeof(data_buff), 20);
Литература:
switch(data_buff[2] & 3) { case(0): printf("Äèñê ïóñòîé\n"); break; case(1): printf("Ìîæíî äîïèñûâàòü èíôîðìàöèþ\n"); break; case(2): printf("Çàïèñü íåâîçìîæíà\n"); break; default: break; }
82
}
send_cmd(reserv_track_cmd, 10, SG_DXFER_NONE, ↵ NULL, 0, 20); return;
1. ATAPI DVD Devices, ftp://ftp.seagate.com/sff/INF-8090.PDF 2. SCSI MultiMedia Command Set, http://www.t10.org/ftp/t10/ drafts/mmc5/mmc5r01.pdf. 3. Мешков В. Пакетные команды интерфейса ATAPI. – Журнал «Системный администратор», № 9(22), сентябрь 2004 г. – 70-84 с. 4. Мешков В. Запись дисков CD-R/RW в Linux. Часть 1. – Журнал «Системный администратор», № 11(24), ноябрь 2004 г. – 56-62 с. 5. Мешков В. Запись дисков CD-R/RW в Linux. Часть 2. – Журнал «Системный администратор», № 12(25), декабрь 2004 г. – 68-75 с.
bugtraq Обход ограничений во многих персональных межсетевых экранах Программа: ZoneAlarm/ZoneAlarm Pro версии до 5 ветки, Kerio все версии, Agnitium Outpost Firewall все версии, Kaspersky Anti-Hacker все версии, Look ’n’ Stop все версии, Symantec’s Norton Personal Firewall все версии, Panda Platinum Internet Security все версии, Omniquad Personal Firewall все версии. Опасность: Высокая. Описание: Обнаружена уязвимость во многих персональных межсетевых экранах. Злоумышленник может обойти ограничения безопасности и выполнить произвольные действия на уязвимой системе. Уязвимость обнаружена в приложениях, которые используют ярлыки или предоставляют графический интерфейс для изменения текущих настроек межсетевого экрана и не запрашивают ввод пароля. Злоумышленник может с помощью троянской программы или другого приложения, способного использовать «Sending Key Method» и «Mouse Control Method», обойти ограничения безопасности. Большинство брандмауэров используют опцию запоминания настроек и автоматически генерируют соответствующие правила, что позволяет злоумышленнику лишь однократно использовать эту уязвимость. Решение: Исправление существует лишь для ZoneAlarm (5 версия не уязвима).
Удаленное выполнение произвольного кода в HTML Help ActiveX control Программа: Microsoft Windows 2000 Service Pack 3, Microsoft Windows 2000 Service Pack 4, Microsoft Windows XP Service Pack 1, Microsoft Windows XP Service Pack 2, Microsoft Windows Server 2003. Опасность: Критическая. Описание: Уязвимость в HTML Help ActiveX control позволяет удаленному пользователю раскрыть чувствительную информацию или выполнить произвольный код на уязвимой системе. Удаленный атакующий может сконструировать специально обработанную веб-страницу, которая может использоваться для выполнения произвольного кода на системе пользователя, просматривающего эту страницу. URL производителя: http://www.microsoft.com. Решение: Установите соответствующее обновление.
Получение административных привилегий в Oracle Database Server Программа: Oracle Database Server 9i, 10g. Опасность: Средняя. Описание: Уязвимость позволяет удаленному авторизованному пользователю получить административные привилегии на сервере баз данных. Удаленный авторизованный пользователь может внедрить PL/SQL-команды и получить административный доступ к базам данных. URL производителя: http://www.oracle.com. Решение: Установите обновление с сайта производителя.
№1, январь 2005
Удаленное выполнение произвольного кода в Indexing Service в различных версиях Microsoft Windows Программа: Microsoft Windows XP Service Pack 1, Microsoft Windows Server 2003. Опасность: Критическая. Описание: Уязвимость в Indexing Service позволяет удаленному пользователю выполнить произвольный код на уязвимой системе. Удаленный атакующий может сконструировать специально обработанный запрос к службе индексирования (Indexing Service), чтобы выполнить произвольный код на уязвимой системе с привилегиями системы или вызвать отказ в обслуживании. Уязвимость может эксплуатироваться удаленно, так как Служба индексирования может быть сконфигурирована через Internet Information Service. Патч также выпущен для Windows 2000 Server, однако эта система неуязвима. Подробнее смотрите соответствующее уведомление. URL производителя: http://www.microsoft.com.
Переполнение буфера в службе LDAP на Hitachi Directory Server Программа: Hitachi Directory Server 2 Опасность: Средняя. Описание: Уязвимость в службе LDAP на Hitachi Directory Server позволяет злоумышленнику выполнить произвольный код на целевой системе. Удаленный пользователь может отослать специально сформированный LDAP-пакет целевой службе, вызвать переполнение буфера и аварийно завершить работу LDAPслужбы или выполнить произвольный код. URL производителя: http://www.hitachi-support.com. Решение: Исправление описано по адресу: http://www.hitachisupport.com/security_e/vuls_e/HS05-001_e/01-e.html.
Отказ в обслуживании при обработке WCCP-сообщений в Squid Программа: Squid 2.5. Опасность: Средняя. Описание: Уязвимость обнаружена в Squid при обработке WCCP-сообщений. Удаленный пользователь может вызвать отказ в обслуживании. Удаленный пользователь может послать специально сформированный WCCP_I_SEE_YOU-пакет с значением поля number of caches, не равным промежутку 1-32 и подменным адресом. Если WCCP разрешен на системе (WCCP не является настройкой по умолчанию), то Squid аварийно завершит свою работу. URL производителя: http://www.squid-cache.org Решение: Установите патч от производителя: http:// w w w . s q u i d - c a c h e . o r g / Ve r s i o n s / v 2 / 2 . 5 / b u g s / s q u i d 2.5.STABLE7-wccp_denial_of_service.patch.
Составил Александр Антипов
83
образование
ОБУЧЕНИЕ ПРИ ПОМОЩИ ATutor СЕРГЕЙ ЯРЕМЧУК C развитием средств коммуникации наметился повышенный интерес к различным методам дистанционного обучения. Удобства налицо, обучаемому нет необходимости тратить время на перемещение к месту занятий, а сам урок можно почитать в любое удобное для себя время, изучив материал полностью или отложив прочтение части на потом. Сейчас можно встретить большое количество разнообразных продуктов, предназначенных для организации такого сервиса. В статье пойдет речь об одном из них – свободном Open Source-решении, позволяющим с минимальными финансовыми затратами собрать подобную систему. ATutor является системой управления обучения – Webbased Learning Content Management System (LCMS). Использование которой позволяет преподавателям легко организовывать различные курсы обучения. Студенты же получают адаптивную и простую среду обучения. Администратору новая система особых хлопот не доставит. Внешний вид можно сменить буквально за пару щелчков мышки, доступность исходного кода и открытые инструменты, применяемые для построения сервера курсов, позволяют в случае крайней необходимости внести и более серьезные изменения. Кроме того, с самого начала разработчиками был взят курс на поддержку продуктом всевозможных стандартов, что позволило бы в будущем легко интегрировать и сторонние разработки. Так, ATutor – первая LCMS, полностью подчиняющаяся спецификации доступности W3C WCAG (Web Content Accessibility Guidelines, http://www.w3.org/WAI/WCAG1AAConformance) 1.0 уровня AA+. Соответствие этим рекомендациям позволяет сделать ресурс доступным, в том числе и для пользователей с различными нарушениями здоровья. Хотя стоит отметить, что с 19 ноября 2004 года доступна следующая версия спецификации W3C WCAG 2.0 (http:// www.w3.org/TR/2004/WD-WCAG20-20041119), поэтому в последнее время ведется работа для достижения полного соответствия стандарту. Также соответствие спецификациям W3C XHTML 1.0 гарантирует, что ATutor при необходимости обеспечит работу или интеграцию с любыми другими приложениями, поддерживающими стандарты. Некоторые такие приложения доступны на сайте проекта, разговор о них пойдет далее. Чтобы иметь возможность использовать курсы, написанные для других e-learning обучающих систем, система поддерживает спецификации IMS (Instructional Management Standards, http://www.imsproject.org) и SCORM (Sharable Content Object Reference Model, http://www.adlnet.org). В настоящий момент основным источником сторонних курсов для пользователей ATutor является TILE learning objects respository (http://barrierfree.ca/tile). Хотя инструменты для работы с ним еще несовершенны, пока реализован поиск и импорт, без проверки целостности. Продукт распространяется по лицензии GPL, домашняя страница проекта http:// www.atutor.ca/atutor.
84
Установка сервера курсов Установка, как и процесс обновления системы, не является сложной. Для возможности дальнейшей работы необходимо будет пройти шесть шагов, каждый из которых должен закончиться успешно. Первоначально необходимо иметь компьютер с: ! Веб-сервером Apache 1.3.x (Apache 2.x разработчиками не рекомендуется). ! PHP версии > 4.2.0 (лучше > 4.3.0) с включенной поддержкой zlib и MySQL. ! MySQL версий > 3.23.x и > 4.0.12 (версии 4.1.x и 5.x официально не поддерживаются). Как видите, об операционной системе в требованиях не сказано ни слова. И это правильно, т.к. все вышеперечисленные компоненты могут работать как на различных вариантах UNIX-систем, так и под управлением MS Windows. Я тестировал работу сервера ATutor на компьютере с установленной Windows XP Professional, и в нескольких дистрибутивах GNU/Linux, включая и такой экзотический в наших краях, как Fermi Linux. Но в качестве рабочей платформы был выбран проверенный временем Slackware 9.1 с некоторыми обновлениями. На момент написания статьи была актуальна ATutor1.4.2. Размер системы составлял чуть более 1 Мб. Для установки требуется распаковать архив в корневой каталог документов веб-сервера. Например, для Slackware. # cd /var/www/htdocs # tar xzvf /home/source/ATutor-1.4.2.tar.gz
После чего в текущем каталоге образуется подкаталог ATutor. Теперь запускаем веб- и MySQL-серверы и набираем в строке браузера http://IP_your_server/[path_to_atutor]/ ATutor/. В качестве клиентского браузера хорошо подходят большинство из базирующихся на коде Mozilla (Netscape 7+, Firefox, Galeon) и Microsoft Internet Explorer 4+, а вот как будет выглядеть страница в Opera и Konqueror, уже зависит от версии. Если Apache настроен правильно, то вы увидите картинку (рис. 1) и для продолжения установки достаточно нажать на ссылку.
Ðèñóíîê 1
Если вместо данной страницы будет выведен исходный текст документа или показано содержимое каталога, то измените настройки в файле httpd.conf. В первом случае в файле должны быть раскомментированы следующие строки (возможно, они будут находиться во внешнем файле, подключаемом инструкцией Include).
образование LoadModule php4_module libexec/libphp4.so AddModule mod_php4.c AddType application/x-httpd-php .php
Во втором случае в директиве DirectoryIndex должен быть обязательно указан параметр index.php. DirectoryIndex index.html index.php
Если что-то не получается, в Интернете достаточно много материала на тему LAMP (Linux+Apache+MySQL+PHP). Теперь осталось пройти все шесть шагов. На первом этапе система проверит установленное ПО и опции, с которыми оно собиралось. Отсюда же можно начать установку либо обновить существующую систему. На следующем шаге указываем параметры подключения к MySQL, далее создаем учетную запись администратора сервера, корректируем в случае необходимости данные сервера курсов и создаем пользовательскую учетную запись. Установка проблем вызвать не должна, так как в случае неудачи программа дает вполне внятную подсказку. Например, смотрите рис. 3 и рис. 4, система предупреждает, что не может записать информацию в файл config.inc.php и предлагает изменить параметры доступа к данному файлу сhmod a+rwx (по окончанию процесса установки все надо вернуть на свои места chmod a-xw). Теперь можно зайти на сервер, использовав введенный во время установки логин и пароль.
Что умеет ATutor? ATutor поддерживает три типа пользователей – админист-
ратор, инструктор и ученик. В зависимости от того, в какой роли прописан зарегистрировавшийся, система сама выберет интерфейс. Администратор обладает самыми большими правами, но интерфейсом обделен. После настройки сервера курсов его основная задача состоит в обновлении, локализации, коррекции персональных учетных записей, изменений привилегий доступа, установке новых тем оформления, сборе статистики, защите контента. Также он может создавать новые категории курсов, при этом за каждой категорией может быть закреплена своя тема. Инструкторы имеют доступ ко всем инструментам обучения, могут создавать содержание в текстовом или html-формате (в том числе и в WYSIWYG-режиме), а также импортировать сторонние или экспортировать уже имеющиеся разработки (как в виде полных курсов, так и виде индивидуальных модулей) для использования в других подобных продуктах. Курсам могут быть выставлены предпочтения, касающиеся в основном удобства просмотра материала, на основе собранной статистики будет произведена оптимизация содержания и структуры курса. Система поддерживает три вида курсов: публичные – доступные всем, защищенные – требующие регистрации, и частные, требующие кроме регистрации подтверждения доступа инструктором. Курсы, доступные текущему пользователю, отображаются в «Browse Courses». Экспорт содержания возможен в IMS/SCORM-совместимые пакеты, которые могут просматриваться автономно и/или добавляться в другую e-learning систему. Для связи с учениками реализовано
Ðèñóíîê 2
№1, январь 2005
85
образование несколько возможностей. Здесь и опросы общественного мнения, новости, сообщения и тематические форумы. Для проверки усвоения материала могут быть созданы тесты. Часть привилегий по обслуживанию курсов может быть передана помощникам из числа учеников. Дополнительно с версии 1.4 в ATutor было интегрировано два элемента, расширяющих возможности AChecker и ACollab. AChecker – экспериментальная разработка Adaptive Technology Resource Center (http://atrc.utoronto.ca), позволяющая определять доступность ресурсов в сети. ACollab (http://www.atutor.ca/acollab) представляет собой единую рабочую среду для групп пользователей, занимающихся совместными исследованиями и разработкой документации. Кстати, он может использоваться и как самостоятельное приложение. Все вышеперечисленное позволяет создать удобную среду обучения с адаптивной навигацией, поиском, с контекстной и обычной справкой, словарем, средствами коммуникации – почта, чат, форум и кнопка Users Online, выводящая список зарегистрированных в данный момент пользователей. По умолчанию интерфейс только английский. Для остальных языков используются языковые модули, которые устанавливаются отдельно. Модуль русского языка лежит по адресу http://prdownloads.sourceforge.net/atutor/atutor.1.4.2.ru? download. Хотя, по данным на сайте, перевод еще не закончен. Если нужного языка в списке нет и есть желание перевести, то перед началом работы следует ознакомиться с документом «Thing You Should Know Before Translating», находящимся на сайте проекта.
Ðèñóíîê 3
86
ATutor включает ряд технологий, гарантирующих, что содержимое будет доступно всем потенциальным пользователям, включая тех, кто использует для доступа в Интернет медленные каналы, ранние версии веб-браузеров и старые мониторы. Для этого применяется сокрытие лишних элементов управления, динамическое меню, метки полей формы и альтернативная навигация, фиксация последней позиции, набор горячих клавиш. Все это позволяет пользователю сразу переходить к содержимому. Также полезным для медленных каналов является возможность отключения изображений с выводом альтернативного текста. Пользователям с плохим зрением подойдут темы с большими шрифтами и возможность увеличения изображения в браузерах, поддерживающих эту функцию. Кроме упомянутых в статье add-on, есть еще и другие разработки, их интеграция в ATutor планируется в будущем. Одной из них является ATalker (http://www.atutor.ca/atalker), представляющий собой text-to-speech-сервер, основой которого послужил festival (http://www.cstr.ed.ac.uk/projects/ festival). В ATutor он будет использоваться для озвучки уроков, что может быть полезно, например, ученикам со слабым зрением. ATutor – полноценный, легко расширяемый и адаптируемый, свободнодоступный продукт, построенный на открытых технологиях, который может с успехом применяться как в небольших организациях, так и для учреждений, представляющих свои материалы в Интернете. Более полную информацию о продукте можно найти на сайте проекта.
образование
Ðèñóíîê 4
Ðèñóíîê 5
№1, январь 2005
87
образование
ВОССТАНОВЛЕНИЕ NTFS – UNDELETE СВОИМИ РУКАМИ Меня смущает то, что сырые продукты создаются на интуиции и на гениальности их создателей. Но ведь за ними остается выжженная земля! Если OS/360 оставила за собой шлейф идей, людей, что оставляет за собой Windows? Алексей Бабий «Из жизни первобытных программистов»
Продолжая говорить о NTFS, сегодня мы рассмотрим технику восстановления удаленных файлов с помощью простейшего дискового редактора (типа Disk Probe) и утилиты chkdsk, а также дадим несколько советов по поводу создания собственного инструментария, который может быть запрограммирован на любом языке, имеющем доступ к win32 API.
КРИС КАСПЕРСКИ Надежность NTFS – это одно, а ошибочно удаленные файлы – совсем другое. Файловая система, даже такая мощная, как NTFS, бессильна защитить пользователя от себя самого. Но вот предусмотреть «откат» последних выполненных действий она вполне может (тем более что транзакции и журналирование в NTFS уже реализованы). До совершенства остается всего лишь шаг. Увы! Microsoft топчется на месте, все никак не решаясь его сделать (задел, оставленный для будущих версий?). «Защита» от непреднамеренного удаления реализована исключительно на интерфейсном уровне, а это не только неудобно, но и ненадежно. Хорошо, если удаленный файл сохранился в «Корзине», но что делать, если там его нет? Эта статья рассказывает о методах ручного восстановления файлов, в том числе и с отсутствующей файловой записью, когда «покойника» приходится собирать по кластерам.
Внутри FILE_DISPOSITION_INFORMATION IRP_MJ_SET_INFORMATION/ FILE_DISPOSITION_INFORMATION – это пакет, посылаемый драйверу при удалении файла (имейте это в виду при дизассемблировании). Что-
88
бы уметь восстанавливать удаленные файлы, необходимо отчетливо представлять, что происходит в процессе удаления файла с NTFS-раздела, а происходит при этом следующее: ! корректируется файл /$MFT:$BITMAP, каждый бит которого определяет «занятость» соответствующей файловой записи (FILE Record) в MFT («0» – запись не используется); ! корректируется файл /$BITMAP, каждый бит которого определяет «занятость» соответствующего кластера («0» – кластер не используется); ! файловые записи, соответствующие файлу, помечаются как удаленные (поле FLAG, находящееся по смещению 16h от начала FILE Record сбрасывается в ноль); ! ссылка на файл удаляется из двоичного дерева индексов (технические подробности этого животрепещущего процесса здесь опускаются, поскольку восстановить таблицу индексов вручную сможет только гуру, да и зачем? в NTFS индексы играют вспомогательную роль – проще переиндексировать директорию заново, чем восстанавливать сбалансированное B*tree-дерево);
образование ! обновляется атрибут $STANDART_INFORMATION каталога, хранившего удаляемый файл (время последнего доступа и т. д.); ! в /$LogFile обновляется Sequence Number (изменения, происходящие в журнале транзакций мы не рассматриваем); ! Update Sequence Number следующих файловых записей увеличивается на единицу: сам удаляемый файл, текущий каталог, /$MAF, /$MFT:$BITMAP, /$BITMAP, /$BOOT, /$TRACKING.LOG. Каталоги удаляются практически точно так же, как и файлы (с точки зрения файловой системы, каталог тоже файл, только особый – с двоичным B*tree-деревом индексов внутри). Ни в том, ни в другом случае физического удаления файла не происходит, и он может быть легко восстановлен до тех пор, пока не будет затерта принадлежащая ему FILE Record, хранящая резидентное тело файла или список отрезков (run-list) нерезидентного содержимого. Утрата FILE Record очень неприятна, поскольку в этом случае файл придется собирать по кусочкам руками, и чем сильнее он фрагментирован – тем сложнее эта задача. В отличие от FAT, NTFS не затирает первого символа именем файла, чем значительно упрощает свое восстановление.
(Update Sequence Number-n-Array) переместился на шесть байтов вперед, а его место было отдано под выравнивание и поле номера текущей файловой записи (Number of this MFT Record). Восстанавливающая утилита должна не только поддерживать вашу версию файловой системы, но и безошибочно отличать ее ото всех остальных (при обновлении Windows 2000 до Windows XP обновления файловой системы не происходит вплоть до переформатирования диска). Попробуй потом объясни начальству, «это не я, это она все испортила!». Наконец в момент удаления файла утилит для его восстановления может просто не оказаться под рукой (что поделаешь – закон подлости!), и тогда приходится рассчитывать только на свои силы.
Автоматическое восстановление файла Утилиты, восстанавливающие удаленные файлы, не входят в комплект штатной поставки Windows NT, и их приходится приобретать отдельно (а ведь в MS-DOS такая утилита была!). Опасаясь угробить файловую систему окончательно, большинство из них избегает прямой записи на диск – вместо этого вам предлагается считать удаленный файл и переписать его в другое место (но только не на сам восстанавливаемый раздел). Не слишком-то удачное решение! А если на остальных дисках свободного места нет или восстанавливаемый диск имеет всего лишь один логический раздел? Предположим, вам необходимо восстановить базу данных в несколько гигабайт. Можно, конечно, подключить второй винчестер, скопировать ее туда, а затем обратно, но сколько же это займет времени, не говоря уже о том, что сервер лучше не выключать, а горячую замену поддерживают далеко не все жесткие диски! Другой недостаток подобных утилит – слишком медленная работа. Вместо того чтобы найти один-единственный файл, имя которого нам известно, они проводят полномасштабные маневры, сканируя весь раздел целиком. При работе с большими дисками на это уходит от одного до нескольких часов впустую потраченного времени. С другой стороны, утилиты, вносящие изменения непосредственно в саму NTFS, рискуют серьезно повредить дисковый том, после чего ему не помогут даже профессионалы. Настоящие хакеры не доверяют никакому коду, кроме своего собственного, особенно если исходные тексты недоступны, а документация туманна и двусмысленна. Различные версии NTFS отличаются друг от друга. Последние радикальные изменения произошли в Windows XP (NTFS версии 3.1) – массив последовательности обновления
№1, январь 2005
Ðèñóíîê 1. Óòèëèòà GetDataBack çà âîññòàíîâëåíèåì óäàëåííûõ ôàéëîâ
Ручное восстановление файла по FILE Record Начнем с простейшего. Файл только что удален, и принадлежащая ему FILE Record еще не затерта. Как найти его на диске? Существует два способа – «теоретический» и «практический». Теоретический исключительно надежен, но требует дополнительных телодвижений, которых можно избежать, приняв ряд практических допущений. Теоретически: извлекаем из boot-сектора указатель на MFT, извлекаем из нее первую запись (она описывает $MFT), находим атрибут $DATA (80h), декодируем список отрезков (data runs) и последовательно читаем все записи в MFT, анализируя содержимое атрибута $FILE_NAME (30h) – имя файла (кстати, таких атрибутов у файла может быть несколько). Этот же атрибут хранит ссылку на материнскую директорию – если несколько одноименных файлов удалены из различных директорий, мы должны разобраться, какой из них наш. Практически: в девяти из десяти случаев $MFT-файл не фрагментирован и располагается практически в самом начале диска. Имена файлов хранятся по смещению EAh от начала сектора, в начале которого расположена сигнатура «FILE*» («FILE0» – в NTFS 3.1). Поэтому мы просто запускаем любой дисковый редактор (например, Disk Probe из комплекта Support Tools от Microsoft), вводим имя восстанавливаемого файла в юникоде и ищем его по смещению EAh (в NTFS 3.1 – F0h) от начала сектора.
89
образование Когда же искомое вхождение будет найдено, смотрим: находится ли в начале сектора сигнатура «FILE*»/«FILE0», и если нет – продолжаем поиск. Двухбайтовое поле по смещению 16h от начала сектора содержит флаги записи: 00h – запись не используется или была удалена, 01h – запись используется и описывает каталог, 02h – запись используется и описывает директорию. Встречаются и другие значения (04h, 08h… что они обозначают – неизвестно, может быть, вы сможете пролить свет на этот вопрос?).
Ðèñóíîê 2. Ðó÷íîå âîññòàíîâëåíèå ôàéëà ñ ïîìîùüþ Disk Probe C:\chkdsk D: /F Тип файловой системы: NTFS. Проверка файлов завершена. Проверка индексов завершена. Восстановление потерянных файлов. Восстановление потерянного файла test.txt в файле каталога 5 Замена неправильного идентификатора безопасности для файла 29 Проверка дескрипторов безопасности завершена. Исправление ошибок в атрибуте BITMAP основной таблицы файлов. Windows сделала изменения в файловой системе. 1068290 КБ всего на диске. 20 КБ в 2 файлах. 4 КБ в 9 индексах. 0 КБ в поврежденных секторах. 7894 КБ используется системой. 7392 КБ занято под файл журнала. 1060372 КБ свободно на диске. Размер кластера: 2048 байт. Всего кластеров на диске: 534145. 530186 кластеров на диске.
Ðèñóíîê 3. Âîññòàíîâëåíèå óäàëåííîãî ôàéëà ïðè ïîìîùè chkdsk
Исправляем 00h на 01h, записываем изменения и… Ничего не выходит?! А что вы хотели! Ведь помимо этого необходимо еще, во-первых, сообщить файлу /$MFT:$BITMAP, что данная MFT-запись вновь используется, во-вторых, отобрать у файла /$BITMAP номера кластеров, принадлежащие восстанавливаемому файлу, в-третих, перестроить двоичное дерево индексов, хранящее содержимое каталога. Первые два пункта не проблема, но вот над последним придется попыхтеть. Или… просто запустить chkdsk с ключом /F. Он самостоятельно найдет «потерянный» файл и внесет все необходимые изменения в файловую систему. От нас потребуется только установить флаг по смещению 16h в единицу, а остальное – его забота. После этих нехитрых манипуляций файл оказывается в своем родном каталоге. Восстановленный!
90
Разгребая кластерные обломки С нерезидентными файлами, хранящими свое тело вне MFT, ситуация обстоит не так плачевно, хотя проблем тоже хватает. Порядок размещения файла на диске хранится в runlist внутри файловой записи в MFT (теперь уже затертой), и потому возможен лишь контекстный поиск по содержимому. Запускаем диск-редактор, вводим последовательность, заведомо содержащуюся в удаленном файле, но не встречающуюся во всех остальных, и нажимаем «search». Для ускорения поиска можно искать только в свободном дисковом пространстве (за это отвечает файл /$BITMAP). Известные мне редакторы пренебрегают этой возможностью (а зря!), однако утилиту «продвинутого» поиска несложно написать и самостоятельно. Нефрагментированные файлы восстанавливаются элементарно. Просто выделяем группу секторов и записываем ее на диск (только ни в коем случае не на сам восстанавливаемый том!). Единственная проблема – как определить оригинальную длину? Некоторые типы файлов допускают присутствие «мусора» в своем хвосте (и тогда нам остается следовать правилу «лучше перебрать, чем недобрать»), а некоторые нет! Если конец не удается определить визуально (например, pdf-файлы завершаются сигнатурой «%%EOF»), проанализируйте заголовок файла – среди прочей полезной информации обычно там присутствует и его размер. Тут все зависит от структуры конкретного файла, и универсальных рекомендаций дать невозможно. Если файл фрагментирован – ситуация практически безнадежна. Чтобы собрать разрозненные цепочки кластеров воедино, необходимо хорошо знать содержимое удаленного файла. В этом смысле NTFS восстанавливается намного хуже, чем FAT. Последовательность фрагментов файла, хранящаяся в File Allocation Table в виде однонаправленного списка, очень живуча. Если список не поврежден, достаточно лишь найти его первый элемент (а сделать это проще простого, поскольку он будет указывать на заголовок файла с вполне предсказуемым содержимым). Даже если список «разрубить» на несколько частей, они продолжат жить собственной жизнью и нам останется лишь подобрать комбинацию, как их правильно склеить воедино. Список гибнет лишь при полном затирании FAT, что случается, прямо скажем, нечасто. В NTFS же порядок фрагментов файла хранится в крохотных списках отрезков, и их гибель – обычное дело, после чего мы остаемся один на один с миллионом беспорядочно разбросанных кластеров. Текстовые файлы восстанавливаются без труда, но что делать, если это электронная таблица, графическое изображение или архив? Без знания стратегии выделения дискового пространства тут никуда. Порядок, в котором драйвер файловой системы находит подходящие свободные фрагменты, не определен и варьируется в зависимости от множества обстоятельств, однако кое-какие закономерности в нем все же присутствуют. Анализируя списки отрезков сильно фрагментированных дисков, мне удалось установить следующее: сначала заполняются самые большие «дыры», двигаясь от конца MFT-зоны к концу диска. Затем драйвер файловой системы возвращается назад и начинает заполнять дыры помень-
образование ше, и так продолжается до тех пор, пока файл не оказывается на диске целиком. Последними заполняются дыры размером в один кластер. Просматривая карту диска, представленную файлом /$BITMAP, мы можем в точности восстановить порядок размещения фрагментов удаленного файла, наскоро собрав их воедино. Во всяком случае, теоретически. Практически же на этом пути нас ждут коварные препятствия. С момента создания восстанавливаемого файла карта свободного дискового пространства могла капитально преобразиться. Всякое удаление файлов высвобождает одну или несколько дыр, хаотично перемешивающихся с дырами восстанавливаемого файла, искажая картину. Как этому противостоять? Сканируем MFT в поисках записей, помеченных как удаленные, но еще не затертых. Декодируем run-list и вычеркиваем соответствующие им фрагменты из списка кандидатов на восстановление. Это существенно сужает круг поиска, хотя количество комбинаций, в которые можно собрать фрагментированный файл, по-прежнему остается велико. Но это еще что… Самое «интересное» начинается, когда на диск одновременно записываются несколько файлов (например, скачиваемых с помощью ReGet из Интернета) или файл постепенно увеличивает свой размер (набираете дипломную работу в Word?), а в это время на диск записываются другие файлы. Когда к существующему файлу дописывается
крошечная порция данных, файловая система находит наименьшую дыру, затем следующую наименьшую дыру и т. д., вплоть до тех пор, пока маленькие дыры не исчерпаются, и тогда наступает черед дыр побольше. Как следствие, файл выходит сильно фрагментированным – это раз. Файл заполняется не от больших дыр к меньшим, а наоборот (т.е. происходит инверсия стратегии размещения) – это два. Маленькие фрагменты одного файла перемешиваются с маленькими фрагментами других файлов – это три. Хуже всего поддаются восстановлению документы, созданные в MS Office, и вот почему: приложение создает большое количество резервных копий редактируемого файла как в текущем каталоге, так и в каталоге %TEMP%. Вот и разберись, какой фрагмент какому файлу принадлежит! Проще всего восстанавливаются ZIP-архивы. Для этого вам даже не потребуется запускать дисковый редактор. Откройте временный файл на запись, сделайте seek на размер свободного дискового пространства, закройте файл. А теперь обработайте его утилитой pkzipfix.exe (или запустите стандартный pkzip.exe с ключом Fix). В «исправленном» файле волшебным образом появятся все уцелевшие ZIP-архивы! Внутренняя структура ZIP-архива такова, что pkzipfix легко распознает даже переупорядоченные блоки, поэтому высокая степень фрагментации ему не помеха. Дефрагментация тоже происходит интересно. Стандартное API-дефрагментации в силу малопонятных ограниче-
Фрагментация и ее исследование Существуют по меньшей мере две методики исследования стратегии выделения дискового пространства: статическая и динамическая. В первом случае мы просто запускаем дисковый редактор (предпочтительно Disk Explorer от Runtime Software) и анализируем run-list уже существующих файлов, записанных в различное время и различными способами (можно, например, скопировать файл с одного места в другое или попеременно увеличивать размер нескольких файлов – стратегии выделения свободного пространства в обоих случаях будут различны). Статический подход полезен тем, что дает бесценный статистический результат для всего тома целиком, однако, определяет лишь конечный результат, но не путь, которым он был достигнут.
Ðèñóíîê 5. Äèíàìè÷åñêèé àíàëèç ñòðàòåãèè âûäåëåíèÿ äèñêîâîãî ïðîñòðàíñòâà, âûïîëíÿåìûé ïðè ïîìîùè äèñêîâîãî ìîíèòîðà Ìàðêà Ðóññèíîâè÷à
Дисковый монитор Марка Руссиновичка (http://www.sys internals.com) позволяет заглянуть в «святая святых» файловой системы и увидеть, как именно она выделяет дисковое пространство для файлов. Особенно интересно запускать его параллельно с дефрагментатором и chkdsk – тайное сразу становится явным.
Ничто так не постоянно, как временное
Ðèñóíîê 4. Ñòàòèñòè÷åñêèé àíàëèç ñòðàòåãèè âûäåëåíèÿ äèñêîâîãî ïðîñòðàíñòâà, âûïîëíÿåìûé ïðè ïîìîùè Disk Explorer îò Runtime Software
№1, январь 2005
Если, несмотря на все усилия, восстановить удаленный файл так и не удается, попробуйте отыскать его резервную копию. Многие приложения создают такие копии, но не все афишируют их присутствие. Не стоит также забывать о файле подкачки, временных файлах, дампе памяти и других источниках, которые могут хранить фрагменты восстанавливаемого файла (а иногда и весь файл целиком). Даже если они уже были удалены, возможно, принадлежащая им файловая запись еще не была затерта и восстановление не займет много времени.
91
образование ний оперирует не единичными кластерами, а блоками! Минимальный размер блока составляет 16 кластеров, причем начало блока должно быть кратно 16 кластерам в файле! Как следствие – количество мелких дыр после дефрагментации только возрастает, а непрерывных областей свободного пространства практически совсем не остается. Кстати говоря, перемещать внутрь MFT-зоны тоже ничего нельзя. «На томе С: свободно 17%, но только 5% доступно для использования дефрагментатора диска. Для эффективной работы дефрагментатор требует по крайней мере 15% доступного свободного места» – знакомое сообщение, не правда ли? «Недоступное» для дефрагментатора место находится внутри MFT-зоны (как мы помним, при форматировании диска под $MFT-файл резервируется 10% от емкости тома, а затем по мере исчерпания дискового пространства $MFT-файл усекается наполовину, и освободившееся пространство заселяется пользовательскими файлами). Таким образом, для гарантированной работы дефрагментатора ему нужно 10% + 15% = 25% свободного дискового пространства. Не слишком ли высокая плата за дефрагментацию? Если же у вас свободно свыше 25%, настоятельно рекомендуется создать на диске временный файл и выполнить seek, чтобы заполнить все более или менее крупные дыры, не давая их изуродовать дефрагментатору (естественно, после дефрагментации этот файл нужно удалить). Кстати говоря, на сжатые файлы ограничение в 16 кластеров не распространяется, поэтому мелкие файлы очень
92
выгодно держать в сжатом состоянии – это существенно уменьшает фрагментацию тома. Почаще дефрагментируйте свой диск! Это не только увеличит быстродействие, но и упростит восстановление удаленных файлов с затертой FILE Record.
Заключение Восстановление файлов – операция несложная, но нудная и кропотливая. Если по долгу службы или в силу иных обстоятельств вам приходится заниматься восстановлением постоянно, процесс можно «механизировать», написав несколько простых утилит. Чтобы получить доступ к логическому разделу в Windows NT, достаточно открыть одноименное устройство с помощью функции: CreateFile("\\.\X:", GENERIC_READ, FILE_SHARE_READ, 0, ↵ OPEN_EXISTING, 0, 0),
где «X:» – буква логического диска (подробности – в MSDN, или, как нынче модно его называть, – Platform SDK). Не думайте, что все уже написано задолго до вас! Утилит, пригодных для профессионального восстановления данных, под NTFS до сих пор нет (во всяком случае в открытой продаже). Те же, что есть, страдают массой нелепых ограничений (например, не могут ограничить диапазон секторного поиска только свободным/занятым пространством). Так что дерзайте! В следующей статье этого цикла мы рассмотрим технику восстановления отформатированных дисков, в том числе и тех, на которые после форматирования что-то писалось.
подписка на I полугодие 2005 Российская Федерация ! Подписной индекс: 81655
Каталог агентства «Роспечать»
!
Объединенный каталог «Пресса России» Адресный каталог «Подписка за рабочим столом» Адресный каталог «Библиотечный каталог» Альтернативные подписные агентства: Агентство «Интер-Почта» (095) 500-00-60, курьерская доставка по Москве Агентство «Вся Пресса» (095) 787-34-47 Агентство «Курьер-Прессервис» Агентство «ООО Урал-Пресс» (343) 375-62-74 Подписка On-line http://www.arzy.ru http://www.gazety.ru http://www.presscafe.ru
!
! Подписной индекс: 87836
!
!
! Казахстан
!
! !
СНГ В странах СНГ подписка принимается в почтовых отделениях по национальным каталогам или по списку номенклатуры АРЗИ: ! Азербайджан – по объединенному каталогу российских изданий через предприятие по распространению печати «Гасид» (370102, г. Баку, ул. Джавадхана, 21)
!
– по каталогу «Российская Пресса» через ОАО «Казпочта» и ЗАО «Евразия пресс» Беларусь – по каталогу изданий стран СНГ через РГО «Белпочта» (220050, г.Минск, пр-т Ф.Скорины, 10) Узбекистан – по каталогу «Davriy nashrlar» российские издания через агентство по распространению печати «Davriy nashrlar» (7000029, Ташкент, пл.Мустакиллик, 5/3, офис 33) Армения – по списку номенклатуры «АРЗИ» через ГЗАО «Армпечать» (375005, г.Ереван, пл.Сасунци Давида, д.2) и ЗАО «Контакт-Мамул» (375002, г. Ереван, ул.Сарьяна, 22) Грузия – по списку номенклатуры «АРЗИ» через АО «Сакпресса» ( 380019, г.Тбилиси, ул.Хошараульская, 29) и АО «Мацне» (380060, г.Тбилиси, пр-т Гамсахурдия, 42) Молдавия – по каталогу через ГП «Пошта Молдавей» (МД-2012, г.Кишинев, бул.Штефан чел Маре, 134) по списку через ГУП «Почта Приднестровья» (МD-3300, г.Тирасполь, ул.Ленина, 17) по прайслисту через ООО Агентство «Editil Periodice» (2012, г.Кишинев, бул. Штефан чел Маре, 134) Подписка для Украины: Киевский главпочтамп Подписное агентство «KSS» Телефон/факс (044)464-0220
Подписные индексы:
81655 по каталогу агентства «Роспечать»
87836 по каталогу агентства «Пресса России»
№1, январь 2005
95
СИСТЕМНЫЙ АДМИНИСТРАТОР №1(26), Январь, 2005 год РЕДАКЦИЯ Исполнительный директор Владимир Положевец Ответственный секретарь Наталья Хвостова sekretar@samag.ru Технический редактор Владимир Лукин Редакторы Андрей Бешков Алексей Барабанов Валентин Синицин РЕКЛАМНАЯ СЛУЖБА тел./факс: (095) 928-8253 Константин Меделян reсlama@samag.ru Верстка и оформление imposer@samag.ru maker_up@samag.ru Дизайн обложки Николай Петрочук 103045, г. Москва, Ананьевский переулок, дом 4/2 стр. 1 тел./факс: (095) 928-8253 Е-mail: info@samag.ru Internet: www.samag.ru РУКОВОДИТЕЛЬ ПРОЕКТА Петр Положевец УЧРЕДИТЕЛИ Владимир Положевец Александр Михалев ИЗДАТЕЛЬ ЗАО «Издательский дом «Учительская газета» Отпечатано типографией ГП «Московская Типография №13» Тираж 8000 экз. Журнал зарегистрирован в Министерстве РФ по делам печати, телерадиовещания и средств массовых коммуникаций (свидетельство ПИ № 77-12542 от 24 апреля 2002г.) За содержание статьи ответственность несет автор. За содержание рекламного обьявления ответственность несет рекламодатель. Все права на опубликованные материалы защищены. Редакция оставляет за собой право изменять содержание следующих номеров.
96
ЧИТАЙТЕ В СЛЕДУЮЩЕМ НОМЕРЕ: «Кто купил Corel Linux?» или Обзор возможностей настольного дистрибутива Xandros Компания Xandros была основана в мае 2001 года в Канаде с целью создания и продвижения на рынок недорогой, дружественной пользователю настольной операционной системы на базе Linux, которая составила бы конкуренцию Microsoft Windows – «Complete Linux Desktop Solution». В августе того же года компания приобрела Corel Linux OS. Именно она легла в основу выпущенного некоторое время спустя Xandros Desktop 1.0. Будучи наследником Corel Linux, Xandros Desktop OS ведет свою родословную от проекта Debian, разработки которого и используются по сей день для поддержания кодовой базы. Таким образом, Xandros, по сути, является коммерческой разновидностью Debian, подобной Libranet GNU/Linux и Linspire, а значит, он совместим с пакетами DEB, репозитариями apt и прочими «прелестями цивилизации». В момент написания данной статьи последней версией Xandros является третья, отличающаяся от своих предшественниц встроенной функцией записи DVD и персональным брандмауэром.
Однако, в связи с ее недоступностью для большей части читателей, мы решили сфокусировать свое внимание на второй версии дистрибутива, распространяющейся в форме редакции OCE.
Обзор интерактивных веб-технологий В данной работе автор, анализируя функциональные возможности различных технологий, позволяющих реализовать двустороннее взаимодействие пользователя с сетевым сервисом, попытался провести классификацию интерактивных веб-технологий и предлагает подробный обзор существующих технологий и программных средств для создания интерактивных HTML-страниц, сравнивая их достоинства и недостатки.
Unformat для NTFS Cлучилось самое страшное: вы потеряли весь NTFS-раздел целиком. Случайно отформатировали или пережили разрушительный дисковый сбой. Где-то там остались миллиарды байт бесценных данных теперь уже недоступных операционной системе. Как вернуть информацию к жизни? В этой статье автор делится советами ручного и автоматического восстановления.
Вы можете приобретать журналы в магазинах и торговых точках г. Москвы по адресам: ! ! ! !
Магазин «Компьютерная и деловая книга» (Ленинский проспект, строение 38). Выставочный компьютерный центр «Савеловский» (Киоск у главного входа). Выставочный компьютерный центр «Буденовский». Книжная ярмарка «Центральная». Mагазин «Деловая и учебная литература» (м. Тульская, Варшавское шоссе, д.9. эт. 5, павильон 515-09). ! ТЦ «Электроника на Пресне». Mагазин «Техкнига» (павильон 8-9). ! Редакция «Учительская газета» (Ананьевский переулок, д. 4/2, стр. 1).
On-line магазины: ! ! ! !
www.allsoft.ru www.linuxcenter.ru www.linuxshop.ru www.bolero.ru
Уважаемые читатели! НЕ ПРОПУСТИТЕ ПОДПИСКУ на первое полугодие 2005 года подробная информация на стр. 95