From: Alexey Plutakhin <Alexey@nnz.ru.>
Date: Mon, 14 Apr 2006 14:31:37 +0000 (UTC)
Subject: Несколько трюков с ng_ipacct
Оригинал: iplab-nnz.ru
Инструмент ng_ipacct, разработанный Романом Палагиным, предназначен
для сбора статистики о трафике и реализует Cisco ip accounting.
Являясь нодой netgraph, он работает полностью в ядре системы, что
существенно снижает требования к системным ресурсам. Снятие и
обнуление статистики происходит с помощью утилиты ipacctctl.
Инструмент ng_ipacct, разработанный Романом Палагиным, предназначен
для сбора статистики о трафике и реализует Cisco ip accounting.
Являясь нодой netgraph, он работает полностью в ядре системы, что
существенно снижает требования к системным ресурсам. Снятие и
обнуление статистики происходит с помощью утилиты ipacctctl.
Для возможности работы с ng_ipacct описанными ниже методами нужно
скомпилировать ядро с опциями:
Классический метод использования ng_ipacct предполагает, соединение
через ng_tee с нодой ng_ether, т.е. трафик считается на ethernet
интерфейсе. Приведем пример соответствующего скрипта, который
поставляется вместе с исходным кодом самой утилиты.
/sbin/kldload ng_ipacct > /dev/null 2>&1
/usr/sbin/ngctl mkpeer rl0: tee lower right
/usr/sbin/ngctl connect rl0: lower upper left
/usr/sbin/ngctl name rl0:lower rl0_acct_tee
/usr/sbin/ngctl mkpeer rl0_acct_tee: ipacct right2left rl0_in
/usr/sbin/ngctl name rl0_acct_tee:right2left rl0_ip_acct
/usr/sbin/ngctl connect rl0_acct_tee: rl0_ip_acct: left2right rl0_out
В первой строке загружается модуль ng_ipacct, остальные строки
иллюстрирует рисунок:
Таким образом, входящий в ethernet интерфейс rl0 трафик с хука lower
попадает на ноду rl0_acct_tee, где происходит его копирование на хук
upper ноды rl0 и на хук rl0_in ноды rl0_ip_acct. В обратном
направлении все происходит аналогично - с хука upper через tee ноду на
хук lower, при параллельном копировании в ng_ipacct. Как видно из
примера, нода tee служит для дублирования потоков данных проходящих
через нее в обоих направлениях.
При кажущейся простоте метода, сложности все же возникают при
необходимости учета трафика на gif и tun интерфейсах, а так же на
интерфейсах, работающих в режиме моста, в виду особенностей их
реализации. Ниже приведены приемы, позволяющие обойти эти проблемы.
Наиболее универсальный способ - это использование правила tee
файервола ipfw.
nodename=ipacct_${IFACE}
hookprefix=${IFACE}
/sbin/kldload ng_netflow
ngctl -f- <<-SEQ
mkpeer ipacct ctl ctl
name .:ctl ${nodename}
### хук для входящего трафика
mkpeer ${nodename}: ksocket ${hookprefix}_in inet/raw/divert
name ${nodename}:${hookprefix}_in ${nodename}_in
msg ${nodename}_in: bind inet/0.0.0.0:3021
### хук для исходящего трафика
mkpeer ${nodename}: ksocket ${hookprefix}_out inet/raw/divert
name ${nodename}:${hookprefix}_out ${nodename}_out
msg ${nodename}_out: bind inet/0.0.0.0:3022
rmhook .:ctl
SEQ
В приведенном примере две ноды типа ksocket отправляют в ng_ipacct
данные, попадающие в соответствующие сокеты 0.0.0.0:3021 и
0.0.0.0:3022. В эти сокеты трафик направляется правилами файервола:
ipfw add 64021 tee 3021 ip from any to room101 via ${IFACE}
ipfw add 64022 tee 3022 ip from room101 to any via ${IFACE}
При этом следует учитывать, что все запрещающие правила, должны
предшествовать правилам tee, т.к. прохождение сетевых пакетов по ipfw
заканчивается на этих правилах, и пакеты считаются принятыми.
Такую же схему можно реализовать используя правила divert и ноду
ng_echo, которая отправляет пришедший поток данных обратно к
источнику. Проиллюстрируем это на примере входящего трафика.
/sbin/kldload ng_netflow
ngctl -f- <<-SEQ
mkpeer tee dummy right2left
name .:dummy divert_tee_in
mkpeer divert_tee_in: echo right echo
mkpeer divert_tee_in: ksocket left inet/raw/divert
name divert_tee_in:left divert_sock_in
msg divert_sock_in: bind inet/0.0.0.0:3021
disconnect dummy
mkpeer divert_tee_in: ipacct left2right rl0_in
name divert_tee_in:left2right ng_ipacct
SEQ
В январе 2005 года Gleb Smirnoff опубликовал патч для ноды ng_ipfw,
позволяющий копировать трафик из ipfw в netgraph, не прибегая к
использованию сокета divert. Это реализуется директивой файервола
ngtee. Приведем пример соединения нод.
Трафик перенаправляется в netgraph следующими правилами ipfw:
ipfw add 100 ngtee 333 ip from any to any in
ipfw add 200 ngtee 444 ip from any to any out
Также существует директива netgraph, которую можно использовать
совместно с ng_echo, аналогично тому, как это делалось в приведенном
выше примере с правилом divert. Проиллюстрируем случай входящего
трафика.
ngctl -f- <<-SEQ
mkpeer ipfw: tee 333 left
name ipfw:333 rl0_tee
mkpeer rl0_tee: ipacct left2right rl0_in
mkpeer rl0_tee: echo right qqq
SEQ
Данному примеру будет соответствовать правило ipfw:
ipfw add 100 netgraph 333 ip from any to any in
Попавший в приведенные правила файервола пакет либо будет принят, либо
продолжит путешествие по правилам ipfw, в зависимости от значения
sysctl переменной net.inet.ip.fw.one_pass (1 - пакет считается
принятым, 0 - сравнение продолжается). При этом автор патча сообщает,
что такой способ доставки трафика в netgraph более эффективен, чем
трюки с tee.
Также отметим, что в случае работы сетевых интерфейсов в режиме моста,
мост должен быть фильтрующим, чтобы пакеты попадали в файервол.
Приведенные методы также должны работать и с модулем ng_netflow.
Добавлю, что описанные решения были проверены на маршрутизаторах
iscompact. Надеюсь, эта статья окажется полезной. Отдельное спасибо
Роману Бесядовскому за советы.
Алексей Плутахин, инженер-разработчик 'Ниеншанц-Телеком'.