*BSD

индекс
131,42

Netgraph ipfw и гибкий учет трафика через netflow

И снова здравствуйте!

Продолжим обзор модулей FreeBSD netgraph.
Сегодня у нас в гостях ng_ipfw, ng_one2many и старый друг ng_netflow.
С их помощью попробуем посчитать трафик по определенным условиям и посмотрим как это можно использовать на практике.

Что за модули?


ng_ipfw.gif
ng_ipfw — модуль, создающий интерфейс для доступа к подсистеме netgraph из фаервола IPFW. При загрузке в ядро, модуль автоматически создает свой узел в пространстве подсистемы netgraph с именем «ipfw:», и может присутствовать только в единственном экземпляре. Ng_ipfw принимает подключения к произвольным номерным хукам, номера хуков указываются в правилах ipfw. Каждый входящий в модуль пакет тэгируется по нескольким параметрам (ipfw правило, интерфейс, направление), для того чтобы его можно было идентифицировать при возврате обратно в ipfw. Не тэгированные пакеты, возвращаемые в фаервол, уничтожаются. Контрольных сообщений модуль не принимает.

ng_one2many.gifng_one2many — модуль, позволяющий распределять пакеты по нескольким подключениям. Он принимает подключения к одному хуку «one» и к многочисленным «many0», «many1», «manyN»… Пока существует два алгоритма распределения пакетов внутри модуля.

1. Пакеты входящие в «one» поочередно выходят через разные «manyN» (xmit_roundrobin). Все пакеты входящие в «manyN» выходят в «one».
2. Пакеты входящие в «one» выходят копиями через все «manyN» (xmit_all). Все пакеты входящие в «manyN» выходят в «one». (похоже на работу ng_hub).

Так же существует алгоритмы определения up/down линков, и возможность их включения/выключения через команды, это нужно для специфичных задач, об этом подробнее в man ng_one2many.

Ng_one2many принимает контрольные сообщения: setconfig, getconfig, getstats, clrstats, getclrstats. В принципе интуитивно понятно. Подробнее в man.

Модуль ng_hole — делает элементарные действия, считает пакетики вошедшие к нему и уничтожает их.

О модуле ng_netgraph я писал в своем прошлом топике FreeBSD Netgraph на примере Ethernet тоннеля..


IPFW


Системным администраторам работающим с FreeBSD рассказывать об ipfw смысла нет, а кто не знает что это может без проблем прочитать в Википедии, да и гугл выдаст тонны информации с примерами и готовыми наработками. Скажу лишь то, что для взаимодействия ipfw и netgraph в ipfw существует два правила ngtee и netgraph, пример:

ipfw add netgraph 10 all from any to any — направит весь трафик попавший в правило в хук ipfw:10 модуля ng_ipfw

ipfw add ngtee 20 ip from any to any — скопирует весь трафик попавший в правило в хук ipfw:20 модуля ng_ipfw

Немного посчитаем


Мы хотим посчитать трафик, проходящий через интерфейс каждого пользователя в обоих направлениях. При этом исключить подсети 192.168.5.0/24 и 192.168.10.0/24 из учета, т.к в них у нас живут бесплатные ресурсы. Пользователи терминируются на интерфейсы «ngX» демоном mpd.

В ipfw это будет выглядеть так:
ipfw table 1 flush
ipfw table 1 add 192.168.5.0/24
ipfw table 1 add 192.168.10.0/24

ipfw add ngtee 10 ip from not "table(1)" to any in via "ng*"
ipfw add ngtee 10 ip from any to not "table(1)" out via "ng*"

Т.е мы копируем в ipfw:10 подсистемы netgraph весь трафик, не принадлежащий сетям, перечисленным в таблице 1.

ng_ipfw_netflow.gif Нарисуем граф. Он достаточно прост.

Создаем простую структуру из модулей ng_ipfw и ng_netflow и ng_ksocket. Т.к это сбор статистики, данные будут идти только в одну сторону, обрабатываться и отправляться в нужное место.

Копируем весь трафик проходящий через IPFW правила в ng_ipfw, который в свою очередь подключим к ng_netflow, подключенный к ksocket и далее к netflow коллектору.

Собираем в системе


Создаем модуль netflow и подключаем его хук iface0 к хуку ipfw 10.
ngctl mkpeer ipfw: netflow 10 iface0
Называем созданный модуль нетфлоу «netflow», он находится по адресу создания «ipfw:10»
ngctl name ipfw:10 netflow
Отправляем модулю «netflow:» команду, принимать через iface0 чистые IP пакеты. (подробнее в моём прошлом топике о модуле ng_netflow)
ngctl msg netflow: setdlt {iface=0 dlt=12}
Созадем модуль ksocket и подключаем его хук inet/dgram/udp к «netflow:» хуку «export».
ngctl mkpeer netflow: ksocket export inet/dgram/udp
Называем созданный модуль «netflow_socket»
ngctl name netflow:export netflow_socket
Отправляем модулю «netflow_socket» команду подключиться к коллектору.
ngctl msg netflow_socket: connect inet/3.3.3.3:9996

Казалось бы все просто — это будет работать, но оказывается не совсем так, как нужно. Пакет вышедший с интерфейса пользователя и вошедший в интерфейс нашего соседнего пользователя посчитается дважды. Тут мы можем перестать считать, например, исходящий трафик… но к нам на помощь приходит модуль ng_one2many.

Новый граф


ng_ipfw_one2many_netflow.gif Т.к ng_one2many умеет работать в режиме roundrobin, и даже делает это по-умолчанию, мы можем вставить его между ng_ipfw и ng_netflow.

Для разделения трафика пополам потребуется подключить one2many хуками many0 и many1 к ng_netflow и ng_hole, т.к обязательное условие распределения пакетов для one2many являются хуки в активном состоянии.

Получится что в учет пойдет только половина пакетов, с маленькой погрешностью, а вторая часть будет уничтожена.

Для второго графа будем использовать новый хук модуля ipfw — 20. Так же при создании графа нужно будет давать узлам новые имена, чтобы они не пересекались с уже созданным выше графом. Создание его аналогично, и подробно описывать его не буду.

В итоге мы получаем итоговые скрипты для работы.


Первый скрипт для сбора графа полного netflow.
#!/bin/sh
case "$1" in
start)
echo "Starting full netflow."
ngctl mkpeer ipfw: netflow 10 iface0
ngctl name ipfw:10 netflow
ngctl msg netflow: setdlt {iface=0 dlt=12}
ngctl mkpeer netflow: ksocket export inet/dgram/udp
ngctl name netflow:export netflow_socket
ngctl msg netflow_socket: connect inet/3.3.3.3:9996
echo "Ok."
exit 0
;;
stop)
echo "Stopping full netflow."
ngctl shutdown netflow_socket:
ngctl shutdown netflow:
echo "Ok."
exit 0
;;
restart)
sh $0 stop
sh $0 start
;;
*)
echo "Usage: `basename $0` { start | stop | restart }"
exit 64
;;
esac


Второй скрипт создает граф учета половины трафика.
#!/bin/sh
case "$1" in
start)
echo "Starting half netflow."
ngctl mkpeer ipfw: one2many 20 one
ngctl name ipfw:20 one2many
ngctl mkpeer one2many: netflow many0 iface0
ngctl name one2many:many0 netflow_half
ngctl mkpeer one2many: hole many1 black
ngctl name one2many:many1 blackhole
ngctl mkpeer netflow_half: ksocket export inet/dgram/udp
ngctl name netflow_half:export netflow_socket_half
ngctl msg netflow_half: setdlt {iface=0 dlt=12}
ngctl msg netflow_socket_half: connect inet/3.3.3.3:9996
echo "Ok."
exit 0
;;
stop)
echo "Stopping half netflow."
ngctl shutdown netflow_socket_half:
ngctl shutdown blackhole:
ngctl shutdown netflow_half:
ngctl shutdown one2many:
echo "Ok."
exit 0
;;
restart)
sh $0 stop
sh $0 start
;;
*)
echo "Usage: `basename $0` { start | stop | restart }"
exit 64
;;
esac


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

ipfw table 1 flush
ipfw table 1 add 192.168.5.0/24
ipfw table 1 add 192.168.10.0/24

ipfw table 2 flush
ipfw table 2 add 192.168.50.0/24
ipfw table 2 add 192.168.51.0/24
ipfw table 2 add 192.168.52.0/24
ipfw table 2 add 192.168.53.0/24

ipfw add ngtee 10 ip from not "table(1)" to any in via "ng*"
ipfw add ngtee 10 ip from any to not "table(1)" out via "ng*"

ipfw add ngtee 20 ip from "table(2)" to "table(2)" via "ng*"


Вот и всё


Спасибо всем, кто героически прочел всю статью.
+15
19 марта 2010, 11:37
43

комментарии (26)

–1
norguhtar #
В linux:
modprobe ipt_NETFLOW hashsize=65536 active_timeout=300
iptables -A FORWARD -s 192.168.0.0/24 -j NETFLOW

+2
LMik #
А у меня в сарае аэроплан. Я про BSD писал.

А как через iptables только половину трафа в нетфлоу отправить?
0
norguhtar #
Через настройку правил. Что не понятно? Модуль добавляет специальную задачу для лить в netflow.
0
LMik #
А покажите пример, интересно, я немного далек от iptables.
0
norguhtar #
В написанном выше примере, в netflow отправляется весь исходящий транзитный трафик от адресов сети 192.168.0.0/24
0
LMik #
А половину как отправить? Я ж об этом спрашиваю.
0
norguhtar #
Половину чего и зачем.
0
nicolnx #
iptables -A FORWARD -i ppp+ -o eth0 -j NETFLOW
iptables -A FORWARD -o ppp+ -i eth0 -j NETFLOW

для трафика междy ppp-интерфейсами

iptables -A FORWARD -i ppp+ -o ppp+ -j NETFLOW

Ну, дополнительные условия по вкусу.

Всегда поражала тяга бздишников к усложнению простых вещей.
0
nicolnx #
про половину — мы считаем в цепочке FORWARD — трафик проходит через нее один раз поэтому отсеивать дубликаты методом костылей и подпорок не нужно
0
LMik #
Не, просто для BSDшников это простые вещи.
0
nicolnx #
27 команд вместо 3 — то же какое-то нездоровое красноглазие ;)
0
LMik #
У всего свои плюсы и минусы. Я привел пример использования и сборки модулей, цель заставить людей делать именно так не преследую.
0
LMik #
Возьмите лучше к себе на работу на пол ставочки ;)
0
norguhtar #
СОРМ четать? ;)
0
LMik #
А больше заниматься нечем? СОРМ читать можно вон индусов нанять :D.
0
norguhtar #
На полставки только чтение СОРМ :]
0
LMik #
ыы, и скока платят?
0
norguhtar #
это секретная информация :]
0
LMik #
Понятно, значит копейки :(
+1
huze #
Мигалку бы дали, можно и за копейки СОРМ читать…
0
parta #
в BSD есть pf, который с pflow/pfflowd экспортит нетфлоу, можно легко выбирать какой трафик учитывать, а какой нет правилами. так что наброс про иптаблес мимо тазика, «простые» варианты есть и в BSD.
0
norguhtar #
А он равзе там модулем ядра это делает? К тому же насколько я помню у pf с производительностью было как-то не очень хорошо.
0
parta #
pflow — ядерный, pfflowd — нет, но последнему это не мешает выполнять свою работу. а сведения о производительности это часом не от источника ОБС (ОднаБабкаСказала)?
0
norguhtar #
Интернет можно считать за ОБС. Вообще если у вас есть подтверждение что оно работает хотя бы не хуже netgraph я с удовольствием почитаю.
0
oleg_bunin #
Коллега, а Вы не хотите сделать доклад на РИТ++ (http://www.ritconf.ru/)?
Если интересно, то я могу выслать подробную информацию.
0
LMik #
Нет, извиняйте, не готов к такому :)

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