Волшебство netgraph. Модуль ng_netflow и графическая структура трафика на Netflow Analyzer 4.

Что же представляет собой netgraph?

Если в двух словах, то netgraph это как высокоуровневый Basic для сетевых сервисов по сравнению с машинным кодом. Идеология netgraph позволяет путем создания визуальных графов из "кубиков" протоколов, портов и сервисов как бы строить взаимодействие сетевых компонентов простым созданием связей между "кубиками".

Надо отметить что netgraph работает на уровне ядра, и, как сказали бы англоязычные братья, this is god damn fast.Надо сказать что к осознанию netgraph я подходил несколько раз. И каждый раз найденная в небольшом количестве рускоязычная документация не раскрывала темы, да и в общем не давала полного понимания принципов работы.


 

netgraph

Из моего примера вы почерпнете технику создания связей для узлов (nodes) сетевых протоколов и интерфейсов и научитесь при помощи модуля ng_netflow отправлять статистику сетевых соединений в формате Cisco на обрабатывающий хост, в моем случае это Netflow Analyzer 4 от AdventNet Inc.

Что нам потребуется для реализации статистики по структуре трафика:
1. FreeBSD роутер (192.168.0.1), с которого будем собирать статистику, ядро скомпилировано с поддержкой netgraph.
2. Windows хост (192.168.0.12), на который будут приходить пакеты в формате Cisco netflow.
3. установленный модуль ng_netflow (/usr/ports/net/ng_netflow)
4. установленный Netflow Analyzer 4 на windows хост, прослушивающий UDP пакеты на порту 9996


Опишем "кубики" netgraph, которые нам потребуются:

1. кубик сетевого интерфейса, в нашем случае fxp0, он создается автоматически. Имеет для хука: lower и upper.
Lower означает работу с протоколами низкого уровня, upper - соответственно верхнего. Нас будет интересовать как раз сетевой поток,
проходящий от нижнего сетевого уровня к верхнему.
2. кубик tee. Его нам потребуется создать вручную. Имеет четыре хука: left, right, left2right и right2left.
Назначение этого кубика - пропускать пакеты с left в right (и наоборот) и дублировать проходящий поток данных в хуки
left2right если нужны данные, которые идут слева направо (исходящий трафик), и right2left если данные идут справа налево(входящий трафик).
3. кубик one2many, название говорит само за себя. Принимает от многих хуков (many0,many1,many2 и т.д.) и передает "собирая" потоки в один хук one.
4. кубик netflow, который будет принимать на себя сетевые потоки снятые при помощи tee у сетевых интерфейсов через хуки iface0, iface1,iface2 и т.д.
Этот кубик будет формировать cisco netflow пакеты, содержащие агреггированную информацию о прошедшем трафике и передавать в хук export.
5. кубик ksocket, стандартный модуль netgraph для отправки пакетов определенному хосту. В нашем случае на хук inet/dgram/udp будут поступать от netflow пакеты для передачи хосту. Управляющим сообщением msg мы зададим хост и порт, на который будут уходить наши пакеты (192.168.0.12:9996).

Создать узел можно при помощи команды mkpeer, при чем создание узла всегда происходит с подключением одного из хуков создаваемого узла
к хуку родительского узла, и правда, зачем нам создавать неподключенный узел? :)

Соединение хуков происходит при помощи команды connect, синтаксис которой таков:
connect перваянода втораянода хукпервойноды хуквторойноды.

Именование хуков и нод следующее. Каждый создаваемый нод безымянный, но имеет индекс, который мы можем увидеть командой list.

Пример:
  Name: ngctl27877      Type: socket          ID: 00000009   Num hooks: 0
  Name: <unnamed>       Type: ksocket         ID: 00000008   Num hooks: 1

Мы можем обратиться к узлу ksocket через его номер (ID) так [8]:
Двоеточие указывает на то, что это нода :) Мы можем дать название ноде.
К примеру, назовем этот же узел как ksocket1.

name [8]: ksocket1
И далее мы уже можем обращаться к нему как к ksocket1:

Полезна команда show, которая нам покажет соединенные хуки

+ show netflow:
  Name: netflow         Type: netflow         ID: 00000007   Num hooks: 2
  Local hook      Peer name       Peer type    Peer ID         Peer hook
  ----------      ---------       ---------    -------         ---------
  export          <unnamed>       ksocket      00000008        inet/dgram/udp
  iface0          one2many0       one2many     00000006        one

Здесь видны какие хуки есть, сколько их, и к каким узлам подключены.

К нодам и хукам мы можем обратиться разными способами. Например, у нас есть два узла: tee (хуки left, right,right2left, left2right) с названием tee1 и one2many (хуки many0,many1,one) с названием one2many1.
Допустим мы хотим соединить tee1 через хук left к хуку many0 узла one2many1, и хук right tee1 к хуку many1 узла one2many1.
Хук left от узла tee1 адресуем как tee1:left. Хук many0 адресуем как one2many1:many0.

+ connect tee1: one2many1: left many0
после того как ноды соединены мы имеем возможность использовать альтернативную адресацию, к примеру, к ноде one2many1 мы можем обратиться через ноду tee1 следующим образом: tee1:left, да-да, как буд-то мы адресуем хук :) Эту конструкцию можно использовать в свежесозданных, еще не именованных узлах.

Итак, начнем.

Подгрузим в ядро модуль netflow:
:~#kldload ng_netgraph

запускаем ngctl
:~#ngctl
и попадаем в командную строку netgraph.
следует проверить, что "кубик" netflow был корректно подгружен:
+ types
There are 20 total types:
      Type name   Number of living nodes
      ---------   ----------------------
        netflow       0

+ mkpeer fxp0: tee lower left
#### создать узел типа tee соединяя их хуки lower и left
+ name fxp0:lower tee0
#### назвать созданный узел tee0
+ connect fxp0: fxp0:lower upper right
#### соединяем хуки upper и right
+ mkpeer tee0: one2many left2right many0
#### создаем узел типа one2many соединяя хуки left2right и many0
+ name tee0:left2right one2many0
#### называем узел one2many0
+ connect tee0:  one2many0: right2left many1
+ mkpeer one2many0: netflow one iface0

#### создаем netflow узел
+ name one2many0:one netflow
+ mkpeer netflow: ksocket export inet/dgram/udp

#### создание узла ksocket, соединяем с netgraph на хук iten/dgram/udp
+ msg netflow: setifindex { iface=0 index=4 }
#### задаем индекс интерфейса (я так понимаю это что-то вроде порядкового номера, под которым он идет в ifconfig)
+ msg netflow:export connect inet/192.168.0.12:9996
### говорим отправлять пакеты на хост сбора статистики

В этом примере рассмотрено подключение к статистике одного интерфейса. Подключение наскольких интерфейсов
происходит аналогично, через tee, one2many и один из свободных хуков ng_netflow (iface1,iface2, ...)

Если все прошло как следует, то наш хост 192.168.0.12 начнет получать netflow пакеты на UDP порт 9996.
Если все прошло не как следует мы вполне можем получить непингуемую машину, которую прийдется лечить перезагрузкой.

Настройка netflow analyzer не представляет никакого интереса, ибо нечего там настраивать ;)
В завершение приведу несколько скриншотов с работающей системы учета трафика.

netflow analyzer 

Следует отметить, что netgraph исключительно мощная система, что доказывает очень известный и популярный продукт MPD VPN для PPTP, который полностью работает на netgraph.