Когда речь заходит о системах учета трафика, невольно вспоминаются сомнительного вида патчи для ядра, вереницы зависимостей, хитрые парсеры лог-файлов на перле, тяжелые SQL.ные базы и приблуды на php. В результате такой конструкции существенно увеличивают
Автор:
Разместил: Amro   Дата: 2006-06-03 20:14
Комментарии: (0)   Рейтинг:
Средняя оценка участников (от 1 до 10): Пока не оценено   
Проголосовавших: 0

Система учета трафика в считанные минуты

Оригинал статьи в журнале Xakep

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

Chillin

Возьмем самый распространенный случай, когда в твой подъезд/универ/офис заведен кабель от прова, выделен статический IP-адрес, а в роли маршрутизатора выступает старенький комп с двумя сетевухами и установленной FreeBSD 5.х. Что касается фряхи, то она у нас (для остроты ощущений) будет не совсем обычной. Мы откажемся от использования штатных файрволов ipfw2/ipfilter и прикрутим OpenBSD.шный pf, по фичам и возможностям не имеющий себе равных среди свободно распространяемых брандмауэров.

Ядра - чистый изумруд

Наличие поддержки интерфейса обратной петли (loopback), сети Ethernet и фильтров пакетов Беркли обязательно:

device loop

device ether

device bpf

Следующим шагом будет объявление директивой options переменных PFIL_HOOKS и RANDOM_IP_ID (генерируем случайное значение в поле ID IP-пакета вместо того, чтобы каждый раз увеличивать его на единицу). Только так мы получим практически полноценную поддержку packet filter нашим ядром:

options PFIL_HOOKS

options RANDOM_IP_ID

Поддержка практически полноценная, так как ALTQ и работа с протоколом IPv6 пока находится в стадии бета-тестирования, но не волнуйся: ни то ни другое нам не понадобится. С помощью утилиты config производим синтаксический анализ конфигурационного файла ядра и создаем компиляционный каталог со всеми необходимыми заголовочными файлами:

# config MIDIAN

Ненадолго отвлекаемся от ядерных экспериментов и устанавливаем packet filter из портов:

# cd /usr/ports/security/pf

# make install clean

Далее переходим в директорию с сырцами и не спешим, так как дедовский метод сборки ядра (make clean && make depend && make && make install) для пятой ветки уже не подходит:

# cd /usr/src

# make buildkernel KERNCONF=MIDIAN

# make installkernel KERNCONF=MIDIAN

Ставим на автомат

В отличие от большинства файрволов, packet filter не использует систему Syslog и регистрирует все события с помощью собственного журнального демона pflogd. Отслеживаемые на псевдоустройстве /dev/pf пакеты перенаправляются на сетевой интерфейс pflog0, откуда, попав в компетенцию pflogd, в двоичном формате tcpdump методично записываются в файл /var/log/pflog.

В конфиге /etc/rc.conf следующими записями разрешаем автоматическую загрузку pf и pflogd при старте системы (последней директивой pf_conf задается путь к файлу с правилами fw):

# vi /etc/rc.conf

pf_enable="YES"

pf_logd="YES"

pf_conf="/usr/local/etc/pf.conf"

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

# mv /usr/local/etc/rc.d/pf.sh.sample /usr/local/etc/rc.d/pf.sh

Создать универсальный набор рулесетов файрвола, ввиду специфики условий работы, не представляется возможным, поэтому опишу только общую часть, которая затрагивает систему NAT и редирект http-трафика:

# vi /usr/local/etc/pf.conf

// внешний сетевой интерфейс

ext_if="fxp0"

// внутренний сетевой интерфейс

int_if="fxp1"

// в таблицы радикса заносим айпишники клиентов и доверенные подсети

table persist file "/usr/local/etc/nat.conf"

table { 192.168.5.0/24, 192.168.7.0/24 }

// NAT.им юзверей (производим трансляцию адресов)

nat on $ext_if from to any -> $ext_if

// заворачиваем на проксик все клиентские http-запросы

rdr on $int_if inet proto tcp from to ! port \

{ 80, 8080, 8101 } -> 127.0.0.1 port 3128

Предлагаю дальнейшую разработку правил firewall.а возложить на твои мужественные/женственные плечи и перейти непосредственно к нашим клиентам, страстно жаждущим получить доступ в Сеть:

# vi /usr/local/etc/nat.conf

192.168.5.2/32

192.168.5.3/32

192.168.5.9/32

Теперь с помощью механизма sysctl включаем перенаправление IPv4-пакетов между сетевыми интерфейсами (скажу по секрету: сетевые подсистемы Linux и BSD спроектированы так, что форвардинг должен работать по дефолту, однако такое поведение запрещено рабочими документами RFC, именно поэтому нам приходится ручками ковырять sysctl):

# vi /etc/sysctl.conf

net.inet.ip.forwarding=1

Чтобы все изменения вступили в силу, перезагружаемся:

# reboot

Считаем трафик, не отходя от кассы

Коллекция портов FreeBSD . настоящая панацея для ленивого юниксоида. Заботливые разработчики подготавливают правила сборки программ, размещая рядом тщательно протестированные diff.чики, конфиги и скрипты. Отказаться от таких удобств было бы просто преступлением:

# cd /usr/ports/net/ipfm

# make install clean

# cd /usr/ports/www/apache13

# make install clean

# mkdir /usr/local/www/data/traffic

Этими нехитрыми командами мы поставили саму считалку трафика и web-сервер Apache. Для отображения пользовательской статистики воспользуемся встроенным средством апача, а именно опцией Indexes директивы Options (листинг каталога при отсутствии index.html).

Но об этом чуть позже, а пока конфигурим его величество ipfm:

# vi /usr/local/etc/ipfm.conf

// определяем внутренний сетевой интерфейс

DEVICE fxp1

// не учитываем локальный трафик

LOG 192.168.5.0/255.255.255.0 NOT WITH 192.168.0.0/255.255.0.0

// задаем имя журнального файла в формате год/месяц_прописью/число

FILENAME "/var/log/ipfm/%Y/%B/%d"

// сбрасываем данные из буферов каждые полчаса

DUMP EVERY 30 minutes

// никогда не очищаем статистику, за нас это делает cron

CLEAR NEVER

// не преобразовываем IP-адреса в доменные имена
// не будем переходить в неразборчивый режим

NOPROMISC

Далее утилитой crontab вызываем текстовый редактор (тот, что определен в переменной окружения $EDITOR) для постановки следующих команд на исполнение в заданное время:

# crontab .e

5,35 * * * * cp .p .R /var/log/ipfm/* /usr/local/www/data/traffic

30 7 1 * * kill .s HUP `cat /var/run/ipfm.pid`

Таким образом, всякий раз при наступлении пятой и тридцать пятой минуты будет происходить рекурсивное копирование каталогов с полученной от ipfm статистикой в директорию, доступную апачу. Сам web-сервер Apache можно вообще не конфигурировать, нас вполне устроят настройки по умолчанию. Хотя особо педантичные товарищи могут проверить, установлена ли опция Indexes для корневого каталога /usr/local/www/data:

# egrep -n 'data|Indexes' /usr/local/etc/apache/httpd.conf

378:

387:Options Indexes FollowSymLinks MultiViews

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

# /usr/local/sbin/ipfm -c /usr/local/etc/ipfm.conf -p /var/run/ipfm.pid

# /usr/local/sbin/apachectl start

Теперь, чтобы посмотреть статистику, достаточно в браузере набрать ip.address.http.server/traffic/.

Подсчитал? Теперь сэкономь!

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

% wget www.squid-cache.org/Versions/v2/2.5/squid-2.5.STABLE4-

YEARMONTHDAY.tar.gz

% tar zxvf squid-2.5.STABLE4-YEARMONTHDAY.tar.gz

% cd squid-2.5.STABLE4-YEARMONTHDAY

После выполнения этой стандартной процедуры начинаем выяснять, с какими параметрами нам нужно скомпилировать кальмара (не советую здесь баловаться с флажками оптимизации, так как squid беспечно работает с памятью, выделяемой под хранимые объекты, sigh):

% ./configure --help | more

% ./configure --prefix=/usr/local/squid --sysconfdir=/etc/squid

--enable-storeio="ufs diskd" --enable-poll --enable-pf-transparent

--disable-ident-lookups --enable-removal-policies="lru heap"

--disable-wccp --enable-err-language=Russian-koi8-r

В данном случае ключевым аргументом сценария configure является параметр.enable-pf-transparent. Именно он дает нам возможность насладиться прелестями прозрачного проксирования. Поясню для тех, кто не в курсе: с помощью прозрачного проксирования для клиентских хостов создается иллюзия прямого соединения с www-узлами интернета (клиентские браузеры не нужно настраивать специальным образом, что очень удобно при наличии в сети большого числа машин), так как все пакеты, в адресах назначения которых содержится 80/tcp порт, будут автоматически перенаправляться squid.у на 3128/tcp порт. С этим разобрались, теперь давай от теории вернемся к созидательной практике, тем более что configure подкинул нам повод для размышлений:

WARNING: Cannot find necessary PF header file

Transparent Proxy support WILL NOT be enabled

Однако не все так просто, как могло показаться на первый взгляд.

Попробуем с этим разобраться:

% grep pf config.log

configure:3843: checking for net/pfvar.h

configure:3849:23: net/pfvar.h: No such file or directory

Как видно из сообщения об ошибке, сценарий configure в директории /usr/include/net не смог найти необходимый для успешной компиляции заголовочный файл pfvar.h. Что ж, придется ему помочь:

# ln -s /usr/local/include/pf/net/pfvar.h /usr/include/net/pfvar.h

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

PF Transparent Proxy enabled

Вот теперь можно переходить к самой компиляции кальмара:

% gmake

И, убедившись в отсутствии ошибок при сборке, инсталлируем:

# gmake install

Для удобства просмотра логов squid.а можно сразу после установки сделать символическую ссылку на более привычный каталог:

# ln -s /usr/local/squid/var/logs /var/log/squid

Игры с кальмаром

Ниже перечислю только первостепенные параметры кэша. Более подробную инфу по настройке squid.а ты найдешь в многочисленных руководствах на сайте squid.opennet.ru.

# vi /etc/squid/squid.conf

// указываем адрес, на котором squid будет слушать клиентские

запросы

http_port 127.0.0.1:3128

// выделяем под кэш требуемый объем оперативки и дискового

пространства (в данном случае 1 Gb)

cache_mem 128 MB

cache_dir diskd /usr/local/squid/var/cache 1024 16 256 Q1=72 Q2=64

// не ленимся вести журналы работы

cache_access_log /usr/local/squid/var/logs/access.log

cache_log /usr/local/squid/var/logs/cache.log

cache_store_log none

// снижаем привилегии

cache_effective_user squid

cache_effective_group squid

// работаем в режиме транспарентной прокси

httpd_accel_host virtual

httpd_accel_port 80

httpd_accel_with_proxy on

httpd_accel_uses_host_header on

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

# pw groupadd squid -g 3128

# pw useradd squid -u 3128 -c "squid caching-proxy pseudo user"

-g squid -d /usr/local/squid -s /sbin/nologin

Назначаем корректные права доступа для кэша, директории с журнальными файлами, а также для специального псевдоустройства, позволяющего программам (скажем, pfctl) контролировать поведение packet filter через системные вызовы ioctl(2):

# chown squid:squid /usr/local/squid/var/cache

# chown squid:squid /usr/local/squid/var/logs

# chgrp squid /dev/pf

# chmod g+rw /dev/pf

Создаем кэш прокси-сервера, иначе говоря, обнуляем структуру каталогов:

# /usr/local/squid/sbin/squid -z

2004/01/30 17:24:28| Creating Swap Directories

# /usr/local/squid/sbin/squid

Альтернативным вариантом будет запуск кальмара с аргументами: ?-D> для пропуска DNS-теста (помогает при модемном соединении либо при неверно настроенном сервере имен) и ?-Y> для более быстрого восстановления после сбоев:

# /usr/local/squid/sbin/squid .DY

Вуаля. Транспарентный проксик созрел и готов принимать наши запросы:

# netstat -na --inet | grep 3128

tcp4 0 0 127.0.0.1.3128 *.* LISTEN

Разбор полетов

Да, все шустро и безглючно воркает, но если ты взглянешь в /var/log/squid, то, скорее всего, тебе станет дурно: за какие-то пару часов работы сквид произведет на свет вагон и маленькую тележку журнальных записей о www-соединениях в неудобочитаемом виде (конечно, все зависит от количества клиентов и интенсивности подключений). Чтобы разобрать эту кашу, никакие калькуляции в уме/в столбик не помогут. Поэтому воспользуемся sarg.ом - одной из самых популярных на сегодняшний день программ для построения детальных html-отчетов на основе лог-файлов squid.а. И здесь нас выручает дерево портов:

# cd /usr/ports/www/sarg

# make install clean

Большинство параметров sarg.а можно оставить без изменений, перечислю только те, на которые стоит обратить особое внимание:

# vi /usr/local/etc/sarg/sarg.conf

// абсолютный путь до лог-файла squid

access_log /usr/local/squid/var/logs/access.log

// директория, куда будут помещаться html-отчеты

output_dir /usr/local/www/data/reports

// не учитываем локальный www-трафик

exclude_hosts 192.168.5.0

// создаем отметки времени в европейском формате

date_format e

// для экономии места перезаписываем отчеты

overwrite_report yes

И, наконец, через crontab передаем демону cron новые задания: каждое первое число месяца производить ротацию логов сквида и ежечасно обрабатывать логи sarg.ом (если ты считаешь, что запускать такие задания от имени суперпользователя несколько рискованно, то используй команду crontab .u username):

# crontab -e

0 8 1 * * /usr/local/squid/sbin/squid -k rotate

0 * * * * /usr/local/bin/sarg -f /usr/local/etc/sarg/sarg.conf

Chillout

Вот так, в сжатые сроки и без единой строчки кода, у нас получилась полноценная система учета трафика. Если будут проблемы/комментарии/идеи - мыль, по возможности отвечу.

Таблицы радикса

Таблицы радикса (radix tables) - это именованные массивы, предназначенные для хранения IP-адресов и целых подсетей. Таблицы очень удобно использовать, когда нужно оперировать большими диапазонами адресов. К примеру, немедленно блокируем все соединения с айпишниками, зарезервированными для внутреннего использования (см. RFC 1918):

table const { 10/8, 172.16/12, 192.168/16 }

block in log quick on $ext_if inet from to any

block in log quick on $ext_if inet from any to

Приручаем VPN

Для того чтобы клиенты могли выходить в инет, используя виртуальные частные сети, нужно с помощью packet filter разрешить исходящие соединения по протоколу gre:

pass out on $ext_if inet proto tcp from any to any flags S/SA keep state

pass out on $ext_if inet proto { udp, icmp, gre } all keep state

Интересные тулзы

pftop (www.eee.metu.edu.tr/~canacar/pftop/) . утилита для мониторинга работы pf в реальном времени.

pfstat (www.benzedrine.cx/pfstat.html) . утилита для сбора статистики pf и построения красивых графиков с использованием библиотеки gd.

hatchet (www.dixongroup.net/hatchet/) . анализатор лог-файлов pf.

INFO

В данном примере fxp0 . это внешний сетевой интерфейс, имеющий выделенный статический IP-адрес, а fxp1 . внутренний интерфейс с айпишником из диапазона адресов класса С (fxp - это драйвер семейства сетевых карт Intel EtherExpress 100).

DANGER

Если в роли шлюза выступает маломощный компьютер, то для более быстрой обработки данных при настройке ipfm не задавай сортировку логов и используй опции NORESOLVE, NOPROMISC.

WWW

pf4freebsd.love2party.net/

robert.cheramy.net/ipfm/

solarflux.org/pf/

www.openbsd.org/faq/pf/index.html

www.aei.ca/~pmatulis/pub/obsd_pf.html

Деликатный сивисап

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

Конфиг ~/cvs-supfile

*default host=cvsup5.ru.FreeBSD.org

*default base=/usr

*default prefix=/usr

*default release=cvs tag=RELENG_5_1

*default delete use-rel-suffix

*default compress

src-all

ports-all tag=.

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

# /usr/local/bin/cvsup -g -L 2 ~/cvs-supfile

Подробнее об используемых параметрах cvsup:

-g . не используем графическую версию сивисапа;

-L 2 . устанавливаем степень журналирования событий.

Автор: Andrey Matveev