Бортжурнал юниксоида

Anton Karpov

Xakep, номер #063, стр. 063-108-1

(toxa@real.xakep.ru)

Система журналирования событий в подробностях

Залогинься в свою Unix-систему, набери ps waux, если это Linux или BSD, или ps -ef, если это Solaris либо другая реализация System V. Ты увидишь множество процессов, каждый из которых что-то делает. К примеру, это может быть crond, inetd, ntpd, sendmail, sshd и еще масса других демонов, а также процессы ядра системы. И что интересно - все они выводят на стандартные потоки данные, которые регистрируются системой журналирования. Для чего это нужно?

Это сделано для того, чтобы владелец хоста в любой момент времени мог узнать, что конкретно делает каждый из них, а если что-то не работает - выяснить, в чем причина. Логи - история жизни системы, и порой только долгое ковыряние в /var/log помогает выяснить, почему же вдруг провайдер выставил непомерный счет за трафик, и что за клоун всю ночь долбился на все 65535 портов сервера.

Краткая справка

Традиционно за ведение журналов событий отвечает демон syslogd, история которого корнями уходит в институт Беркли и тамошнюю BSD. Syslogd - нечто большее, чем просто демон. Он должен взаимодействовать со всеми демонами, которые запущены в системе, чтобы все они могли протоколировать события. Взаимодействие это происходит через специальный сокет /dev/log. Поэтому любой демон, желающий оставить память о себе в журнале событий, просто пишет в этот файл с определенными аргументами. Системный демон syslogd запускается из инициализационных скриптов при старте системы.

Как и у любого уважающего себя демона, у syslogd есть свой конфигурационный файл. По умолчанию это /etc/syslog.conf, однако ничто не мешает назвать его как угодно, а потом запускать syslogd с ключом -f /path/to/config.file. Именно на файл конфигурации мы обратим свое внимание, а о ключиках, с которыми можно пускать syslogd, можно узнать из man syslogd, благо их немного.

Конфигурирование демона

Каждая строчка syslog.conf состоит из двух записей - правила и действия. В правилах указывается, какая подсистема генерирует события, а также степень подробности, в действиях - что с этими событиями делать. На деле все просто. Основных подсистем всего двенадцать - auth, authpriv, cron, daemon, kern, lpr, mail, mark, news, syslog, user, uucp, однако на практике в основном используют следующие из них: auth - информация о регистрации пользователя в системе ("юзер вася зашел со второй консоли"), authpriv - информация о повышении привилегий в системе ("юзер вася сделал su на рута на второй консоли"), cron - информация о выполняющихся по расписанию заданиях ("в девять утра, как обычно, скрипт опустил firewall, и инет у юзеров кончился"), kern - сообщения ядра ("сетевой интерфейс перешел в promiscious mode"), lpr - сообщения системы печати, mail - сообщения почтовой системы, и т.д.

О назначении подсистемы говорит ее название. Хотя вся эта классификация по большому счету условность. Тут нет ftpd, httpd и т.д. - и не нужно, так как эти демоны сами заботятся о том, сколько и куда писать информации. В общем же случае, это дело программиста - к какому классу отнести своего демона и использовать при написании соответствующий аргумент для функции openlog(3).

Степень подробности - то количество информации, которое будет обрабатываться. Существует восемь классов приоритетов: debug, info, notice, warning, err, crit, alert, emerg, каждый последующий - менее информативный, чем предыдущий. То есть на уровне debug демон выдает огромное число сообщений, по которым можно восстановить его работу во всех подробностях (поэтому так и называется - отладочный), уровень notice - оптимальный (демон выдает только значимые сообщения), emerg - только критичные для работы системы отметки.

Наконец, действие - это то, что должен совершить syslogd, обрабатывая сообщения. Действиями могут быть: запись в файл (/var/log/file.log) - самое популярное, ради чего логи и ведутся, но, помимо этого, логи могут передаваться на удаленный хост (запись вида @loghost), перенаправляться на конвейер другим программам, пересылаться определенным пользователям и/или выводиться на консоль (/dev/console). Под передачей логов на удаленный хост имеется в виду ни что иное, как отправка их на другую машину, где также запущен syslogd, прослушивающий 514/udp порт.

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

подсистема1.уровень1;подсистема2.уровень2;подсистема3.уровень3 <действие>

Здесь точкой разделяется соответствие уровня протоколирования подсистемы, и нескольким таким комбинациям можно сопоставить одно действие, разделив их точкой с запятой. Замечу, что в записи подсистема1.уровень1 определяется следующее: "для подсистемы 1 протоколировать все события уровня 1 и выше". Что логично, если вспомнить, что уровни идут по нарастающей (здесь "выше" - значит, меньше информации). Например, запись daemon.notice;kern.emerg /var/log/messages определяет запись в /var/log/messages всех сообщений уровня notice и выше от всех демонов, а также критичные сообщения ядра (и выше - но выше уже ничего нет). Если же для какого-нибудь демона надо протоколировать только события определенного уровня, перед уровнем ставят "=": mail.=debug. Кроме того, несколько подсистем можно перечислить через запятую, сопоставив им один уровень: mail,news.crit. Также в шаблонах можно использовать значок "*", имеющий тут свое обычное для регулярных выражений значение - "все". *.* /var/log/all.log - указывает писать ВСЕ, что происходит с системой в /var/log/all.log. Спецсимвол "!", предназначенный для инвертирования: mail.!=debug означает все, кроме дебага.

И последнее. Если строка "правило - действие" предваряется названием программы, то эта строка относится только к упомянутой программе. Это очень удобно, когда нужно "выцепить" логи определенной программы (не обязательно демона) в отдельный поток для обработки (писать в отдельный файл). При этом имя программы должно начинаться с "!", например, среди диалапщиков популярна следующая конфигурация (все сообщения ppp писать в отдельный лог-файл):

!ppp

*.* /var/log/ppp.log

Журналирование в примерах

Приведу несколько примеров, подтверждающих, что на самом деле все очень просто:

Конфиг syslogd

# все критичные для работы системы сообщения, а также ВСЕ сообщения ядра выводить на /dev/console. Это, как правило, первая физическая консоль (/dev/ttyv0 у меня в FreeBSD)

*.err;kern.debug;mail.crit /dev/console

# кроме этого, все то, что выше по приоритету, также записывать в messages

*.notice;kern.debug;mail.crit /var/log/messages

# все сообщения подсистемы безопасности писать в отдельный файл

security.* /var/log/security

# все что касается аутентификации - писать в auth.log

auth.info;authpriv.info /var/log/auth.log

# все сообщения почты соответствующих уровней - в maillog

mail.info /var/log/maillog

# я хочу следить за работой cron - поэтому все его сообщения пишутся отдельно

cron.* /var/log/cron

# все критичные сообщения писать всюду куда возможно :), чтобы они не остались незамеченными

*.emerg *

# все сообщения централизованно складываются на сервер протоколирования

*.* @loghost.toxa.lan

# все сообщения моих любимых программ я хочу видеть в отдельных файлах.

!popa3d

*.* /var/log/popa3d.log

!scanlogd

*.* /var/log/scanlogd.log

Для того чтобы демон syslogd заново перечитал свой конфиг, перезагружаться совсем не обязательно, достаточно послать ему сигнал HANGUP:

Для Linux и FreeBSD:

# killall -HUP syslogd

Для NetBSD, OpenBSD и Solaris:

# pkill -HUP syslogd

В общем случае:

# kill -HUP `sed q /var/run/syslogd.pid`

Боремся с пожирателями диска

Грамотно настроить syslogd - это еще полдела. Файлы, в которые постоянно дописывается информация, имеют свойство разрастаться до неприличных размеров, и если не уделять этому должного внимания, в один прекрасный день раздел /var отвалится, взвизгнув, что занято 120% объема :). В Linux, где деление на партиции не так популярно, и часто можно встретить один большой корневой раздел на всю fs (моветон, не делай так никогда), этот момент можно отсрочить (и надолго), зато когда он настанет - настанет и конец всей файловой системе. К сожалению, сам syslogd никаких обработок файлов не производит, поэтому я расскажу про два самых популярных подхода управления журнальными файлами: BSD-шный и линуксовый.

Возьмите у нас в ротацию

Самый удобный способ ротации логов - использование newsyslog. Запускаемый по крону один раз в час/сутки/месяц, он просматривает логи, ищет те, что попали под его правила, и создает новые чистые файлы журнала, инкрементно архивируя старые под именем logfile.?, где ? - цифра, и опционально сжимая их для экономии места. Файл конфигурации по умолчанию - /etc/newsyslog.conf, состоит из следующих основных полей:

1) имя лога - полный путь до файла журнала, за которым нужно следить;

2) владедец:группа и права доступа - атрибуты создаваемого архива;

3) счетчик - глубина инкрементного архивирования;

4) размер - максимальный размер файла;

5) срок - время срабатывания правила.

Размер либо срок могут иметь значение "*" - это значит, что решение об архивировании принимается на основе одного из двух аргументов. Рассмотрим на примере:

/var/log/ppp.log root:network 640 3 100 * Z

Эта строчка говорит о том, что следить нужно за логом ppp.log, созданному архиву присваивать права 640, причем владельцем выставить рута, а группой - network, эту операцию проводить максимум три раза, решение об архивировании проводить на основе размера файла - он не должен превышать 100 Кб, всегда, плюс ко всему сжимать архив (ключ Z) утилитой bzip2 (compess/gzip в зависимости от системы).

Newsyslog, регулярно стартуя по расписанию, будет смотреть, не превысил ли ppp.log размер в 100 Кб, и если превысил - переименовывать старый лог в ppp.log.0, создавая новый пустой ppp.log; сожмет ppp.log.0 в ppp.log.0.bz2 и присвоит архиву права 640, владельца - root, группу - network. Когда размер уже нового ppp.log снова превысит 100 Кб, программа переименует уже существующий ppp.log.0.bz2 в ppp.log.1.bz2 и создаст новый ppp.log.0.bz2 по тому же алгоритму. И так далее, пока самый старый из архивов лога не станет называться ppp.log.3.bz2 (мы же указали счетчик - 3). После чего он удаляется, а третьим становится второй и т.д. Резонный вопрос: как часто нужно запускать newsyslog из cron? На незагруженной машине это можно делать раз в два-три дня, на среднем сервере - раз в день, на загруженной станции - пойдет и раз в час. Newsyslog - очень удобное и гибкое средство, и man newsyslog расскажет тебе еще много интересного.

Решение от туксодрайверов

Newsyslog штатно идет в поставке Free/OpenBSD, тогда как Logrotate присутствует в большинстве дистрибутивов Linux. Занимается он тем же и с подобной же периодичностью запускается по крону. Отличие, как водится, в конфигурации. Здесь главный конфиг /etc/logrotate.conf выглядит примерно следующим образом:

daily
rotate 1
create
compress
include /etc/logrotate.d

Это означает - заниматься обработкой логов каждый день, перелопачивать новые логи один раз перед удалением старых (глубина инкрементного архивирования), создавать новый пустой лог-файл с тем же именем, сжимать созданные архивы. Лаконично, правда? Последняя директива основная - указывает смотреть все дополнительные конфиги, расположенные в каталоге /etc/logrotate.d. В них-то мы и указываем специфические для каждого демона параметры. Например, создадим файл /etc/logrotate.d/httpd:

/var/log/httpd/access.log {

weekly

rotate 5

compress

notifempty

missingok

}

/var/log/httpd/error.log {

weekly

rotate 5

compress

notifempty

missingok

}

Здесь мы указали параметры ротации логов апача. Синтаксис секции: путь до лог-файла, и в фигурных скобках - параметры его обработки. В один конфиг (у нас - httpd) можно занести сколь угодно много таких секций. Удобно создать несколько конфигов, в каждом из которых описать правила ротации логов одного конкретного демона (squid, samba, apache). В нашем случае параметры обработки каждого файла следующие: заниматься обработкой еженедельно (несмотря на то, что logrotate запускается раз в день), утилизировать новый лог пять раз и только потом удалять старые, сжимать полученные архивы, ничего не делать с логом, если он и так пустой, и, наконец, не впадать в панику, если указанный лог не найден.

Журнальный сервачок

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

Альтернативы syslogd

Syslog-ng позволяет обрабатывать логи с использованием регулярных выражений (хорош для фильтрации отдельных сообщений, форматирования журнала протокола и т.п.), а также умеет передавать логи на удаленный хост по TCP.

Socklog работает совместно с daemontools и qmail. Создан для тех, кто уже заменил bind и sendmail на tinydns и qmail и хочет найти адекватную замену и для syslogd.

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

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

www.balabit.com/products/syslog_ng/

www.clueby4.org/minirsyslogd/

smarden.org/socklog/

DANGER

Часто в конфиг добавляют новый файл, забыв его при этом создать (touch /var/log/file.log) или забыв перезапустить syslogd.

DANGER

Иногда созданный лог-файл забывают прописать в newsyslogd/logrotate, в результате чего он остается необработанным и разрастается.