FreeBSD Netgraph, считаем трафик

Опубликовано admin в Пнд, 26/07/2010 - 20:51
В продолжении темы о ядерной подсистеме графов Netgraph FreeBSD Netgraph на примере Ethernet тоннеля (_http://alexandr.sysoev.ru/node/71) попробуем посчитать трафик используя протокол Сisco netflow.

В прошлом обзоре мы познакомились с модулями ng_bridge, ng_ether и ng_ksocket и построили на их базе Ethernet тоннель через интернет, а сегодня я расскажу как, используя дополнительные модули netgraph, посчитать трафик, проходящий по этому тоннелю.

Для учета трафика будем использовать модуль ng_netflow.

Википедия рассказывает

Netflow — протокол, разработанный компанией Cisco и предназначенный для сбора информации об IP-трафике внутри сети.
Маршрутизаторы Cisco генерируют поток netflow, который передаётся на специальный узел, известный как netflow collector.


Наш ng_netflow прикинется маршрутизатором cisco и будет отдавать самый настоящий cisco netflow на коллектор. Коллектор собирает информацию, группирует трафик по потокам, IP адресам, рисует графики и т.п. Зависит от реализации. Я использовал триальный netflow analyzer 7.5.

Опять про кубики


Нам потребуются:

ng_netflow.gif
ng_netflow — Модуль ядерной подсистемы netgraph, реализующий протокол cisco netflow 5 версии. Ng_netflow принимает входящий трафик, идентифицирует его, и создает счетчики активных потоков трафика. Потоки разбираются по протоколам, номерам портов, ToS, интерфейсам. Завершенные потоки отдаются в виде UDP дейтаграммы в Netflow коллектор. Поток считается завершенным: если был получен RST или TCP FIN пакет. Так же для потоков существуют таймауты, по которым поток будет завершен и передан в коллектор. Таймаут активного потока — по-умолчанию 1800 секунд. И таймаут не активного потока по-умолчанию 15 секунд.

Хуки Ng_netflow имеют имена iface0, iface1, iface2, ifaceN. Также соответствующие им out0, out1, out2, outN. И хук экспорта статистики export.

Входящий трафик в ifaceN обрабатывается модулем учета. Если подключен соответственный хук outN, трафик без изменений уходит в него, если не подключен — никуда не уходит. Трафик вошедший в хук outN без изменений проходит к хуку ifaceN, без обработки модулем учета. Т.е фактически на счетчики попадает только входящий трафик в ifaceN. Для управления поведением учета трафика есть настройки, о которых будет рассказано ниже. В итоге через хук export будут выходить UDP дейтаграммы netflow, этот кух обычно подключают к хуку inet/dgram/udp модуля ng_ksocket.

Принимаемые модулем контрольные сообщения, они же команды: info, ifinfo, setdlt, setifindex, settimeouts, setconfig, show. Опишу некоторые, об остальных читайте в man ng_netflow.

Setdlt устанавливает тип интерфейса, подключенного к ifaceN. Из всех возможных вариантов (/usr/src/sys/net/bpf.h)

/*
* Data-link level type codes.
*/
#define DLT_NULL 0 /* BSD loopback encapsulation */
#define DLT_EN10MB 1 /* Ethernet (10Mb) */
#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */
#define DLT_AX25 3 /* Amateur Radio AX.25 */
#define DLT_PRONET 4 /* Proteon ProNET Token Ring */
#define DLT_CHAOS 5 /* Chaos */
#define DLT_IEEE802 6 /* IEEE 802 Networks */
#define DLT_ARCNET 7 /* ARCNET */
#define DLT_SLIP 8 /* Serial Line IP */
#define DLT_PPP 9 /* Point-to-point Protocol */
#define DLT_FDDI 10 /* FDDI */
#define DLT_ATM_RFC1483 11 /* LLC/SNAP encapsulated atm */
#define DLT_RAW 12 /* raw IP */

поддерживаются только Ethernet и голый IP, соответственно варианты 1 и 12. Первый вариант установлен по-умолчанию. Синтаксис «setdlt { iface=0 dlt=12 }»

Settimeouts — устанавливает таймауты активных и не активных потоков, после которых статистика будет отправлена в коллектор. Синтаксис «settimeouts { inactive=15 active=1800 }»


ng_hub.gif
ng_hub — название идет из сетевой терминологии. Ethernet хабы уже давно нигде не используются и в отличии от современных умных Ethernet свитчей умели делать лишь два простых действия: принять пакет на любом интерфейсе, и отправить этот пакет на все интерфейсы.
Этот модуль работает совершенно так же. Принимает данные на любом подключенном хуке с произвольным именем, и отправляет эти данные без изменений на все подключенные хуки. Контрольных сообщений не принимает.


Мы не будем пропускать трафик через ng_netgraph насквозь, пользуясь хуком outN, а используем модуль ng_hub для копирования трафика проходящего по тоннелю в обе стороны.

Составляем граф.


ethernet_over_udp_netflow_scheme.gif


По сравнению со старой (_http://alexandr.sysoev.ru/uploads/images/ethernet_over_udp_scheme.gif), схемой в новой видны изменения:

1. В разрыв между link2 модуля ng_bridge и inet/dgram/udp модуля ng_ksocket вставлен новый модуль ng_hub.
2. К ng_hub подключен новый ng_netflow.
3. ng_netflow подключено к новой копии модуля ng_ksocket, который подключен к коллектору netflow.

Собираем граф в системе.


Со стороны сервера bsd2 изменений никаких делать не придется.
На сервере bsd1 будем собирать всё с начала.

Создаем узел ng_bridge и подключаем к его хуку «link0» хук сетевого интерфейса «em1» «lower».
ngctl mkpeer em1: bridge lower link0
Называем только что созданный узел именем «switch», его можно найти по пути «em1:lower».
ngctl name em1:lower switch
Подключаем к «link1» нашего «switch» upper сетевого интерфейса «em1».
ngctl connect switch: em1: link1 upper
Создаем узел ng_hub и подключаем его к хуку «hublink0» хук «link2» нашего «switch»
ngctl mkpeer switch: hub link2 hublink0
Называем только что созданный узел именем «hub», его можно найти по пути «switch:link2»
ngctl name switch:link2 hub
Создаем узел ng_ksocket и подключаем к его хуку «inet/dgram/udp» «hublink1» нашего «hub»
ngctl mkpeer hub: ksocket hublink1 inet/dgram/udp
Называем только что созданный узел именем «hub_socket», его можно найти по пути «hub:hublink1»
ngctl name hub:hublink1 hub_socket
Создаем узел ng_netflow и подключаем к его хуку «iface0» «hublink2» нашего «hub»
ngctl mkpeer hub: netflow hublink2 iface0
Называем только что созданный узел именем «netflow», его можно найти по пути «hub:hublink2»
ngctl name hub:hublink2 netflow
Создаем ещё один узел ng_ksocket и подключаем к его хуку «inet/dgram/udp» «export» созданного «netflow»
ngctl mkpeer netflow: ksocket export inet/dgram/udp
Называем только что созданный узел именем «netflow_socket», его можно найти по пути «netflow:export»
ngctl name netflow:export netflow_socket
Отправляем команду «bind» нашему «hub_socket», с параметрами. ksocket займет порт 7777 на IP 1.1.1.1.
ngctl msg hub_socket: bind inet/1.1.1.1:7777
Отправляем команду «connect» нашему «hub_socket», с параметрами. ksocket подключится к порту 7777 по IP адресу 2.2.2.2.
ngctl msg hub_socket: connect inet/2.2.2.2:7777
Отправляем команду «connect» нашему «netflow_socket», с параметрами. ksocket подключится к порту 9996 по IP адресу 3.3.3.3. Там должен жить netflow collector.
ngctl msg netflow_socket: connect inet/3.3.3.3:9996
Отправляем команду модулю ng_ether сетевого интерфейса em1 перейти в режим прослушки пакетов, адресованных не ему. Нам ведь теперь необходимо принимать пакеты для устройств находящихся в нашей виртуальной сети.
ngctl msg em1: setpromisc 1
ngctl msg em1: setautosrc 0

Итоговый скрипт сборки графа:
#!/bin/sh
self=1.1.1.1
peer=2.2.2.2
collector=3.3.3.3:9996
port=7777
if=em1

case "$1" in
start)
echo "Starting netgraph switch."
ngctl mkpeer ${if}: bridge lower link0
ngctl name ${if}:lower switch
ngctl connect switch: ${if}: link1 upper
ngctl mkpeer switch: hub link2 hublink0
ngctl name switch:link2 hub
ngctl mkpeer hub: ksocket hublink1 inet/dgram/udp
ngctl name hub:hublink1 hub_socket
ngctl mkpeer hub: netflow hublink2 iface0
ngctl name hub:hublink2 netflow
ngctl mkpeer netflow: ksocket export inet/dgram/udp
ngctl name netflow:export netflow_socket
ngctl msg hub_socket: bind inet/${self}:${port}
ngctl msg hub_socket: connect inet/${peer}:${port}
ngctl msg netflow_socket: connect inet/${collector}
ngctl msg ${if}: setpromisc 1
ngctl msg ${if}: setautosrc 0
echo "Ok."
exit 0
;;
stop)
echo "Stopping netgraph switch."
ngctl shutdown netflow_socket:
ngctl shutdown netflow:
ngctl shutdown hub_socket:
ngctl shutdown hub:
ngctl shutdown switch:
ngctl shutdown ${if}:
echo "Ok."
exit 0
;;
restart)
sh $0 stop
sh $0 start
;;
*)
echo "Usage: `basename $0` { start | stop | restart }"
exit 64
;;
esac


Смотрим результат:
There are 8 total nodes:

[root@bsd1] /root/> ngctl list
Name: em0 Type: ether ID: 00000001 Num hooks: 0
Name: em1 Type: ether ID: 00000002 Num hooks: 2
Name: switch Type: bridge ID: 000002c7 Num hooks: 3
Name: ngctl56729 Type: socket ID: 000002e1 Num hooks: 0
Name: hub_socket Type: ksocket ID: 000002ce Num hooks: 1
Name: hub Type: hub ID: 000002cb Num hooks: 3
Name: netflow_socket Type: ksocket ID: 000002d4 Num hooks: 1
Name: netflow Type: netflow ID: 000002d1 Num hooks: 2


Погоняв немного трафика по тоннелю смотрим:
[root@bsd1] /root/> ngctl msg netflow: info
Rec'd response "info" (805306369) from "[2d1]:":
Args: { Bytes=1722435 Packets=13683 Records used=27 Active expiries=203 Inactive expiries=5566 Inactive timeout=15 Active timeout=1800 }


Так же посмотрев на статистику коллектора, можно увидеть прошедший по тоннелю трафик.

netflow_analyzer.png

Конец


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

В следующих статьях опишу взаимодействие подсистемы netgraph с ipfw, с более практичным способом учета трафика через ng_netflow.

До новых встреч.

Статья взята с http://habrahabr.ru (_http://habrahabr.ru/blogs/bsdelniki/87407/)