Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Разбор пакетов NetFlow v.9 на C#

Anna | 18.06.2014 | нет комментариев
NetFlow это сетевой протокол, сделанный компанией Cisco Systems для учёта сетевого трафика. Особенно распространёнными версиями данного протокола являются 5 и 9. Девятая версия больше эластичная так как применяются образцы, согласно которым присылаются данные. В пятой версии данные присылаются согласно спецификации.
imageСистема сбора информации о трафике по протоколу NetFlow состоит из следующих компонентов:

  • Сенсор. Устройство (маршрутизатор, L3-коммутатор) собирающее статистику по проходящему через него трафику;
  • Коллектор. Занимается сбором данных от сенсора и помещает их в хранилище;
  • Анализатор. Анализирует данные, которые собрал коллектор и формирует отчёты.

О разработки части функций анализатора на C#, а вернее разбор пакетов NetFlow я и расскажу

В качестве сенсора был использован MikroTik маршрутизатор.

Включаем на нем NetFlow для ether1 интерфейса:
/ip traffic-flow set enabled=yes interfaces=ether1

И добавляем коллектор (как правило, коллектор слушает порт 2055, 9555 либо 9995):
/ip traffic-flow target add disabled=no version=9 address=192.168.0.100:9995

Либо тоже самое но через WinBox:
image

Сейчас на компьютер с IP адресом 192.168.0.100 на 9995 порт по UDP (либо SCTP) будут приходить пакетыNetFlow 9 версии. Пакеты приходят и есть с чем трудиться.

Разбор приходящих пакетов

Изучив спецификацию протокола узнаем, что всякий NetFlow пакет (N байт) состоит из:

  1. Packet Header (20 байт) — заголовок пакета, в исключительном экземпляре с полями:
    • Version Number (UInt16 — 2 байта) — номер версии NetFlow, у нас неизменно 9;
    • Count (UInt16 — 2 байта) — всеобщее число записей. Дальше по тексту статей с этим полем былоприключение;
    • sysUpTime (UInt32 — 4 байта) — время в миллисекундах со старта устройства — UpTime;
    • UNIX Secs (UInt32 — 4 байта) — время в секундах с 0000 UTC 1970, при котором отправили пакет;
    • Sequence Number (UInt32 — 4 байта) — счетчик переданных пакетов, он непрерывно возрастает от пакета к пакету, тем самым дозволено проверить потерялись ли пакеты между ними;
    • Source ID (UInt32 — 4 байта) — номер потока данных, деле в том, что со стороны сенсора могут идти несколько потоков данных.
  2. FlowSet (N-20 байт) — образцы, данные… FlowSet`ов может быть несколько либо один. В всякомFlowSet`е есть два непоколебимых от типа передаваемых данных (образец, данные) поля:
    • FlowSet ID (UInt16 2 байта) — для образца это неизменно 0, для опционального образца 1, для данных он равен Template ID и следственно огромнее 255 (от 256 до 65535);
    • Length (UInt16 2 байта) — размер каждого FlowSet совместно с полями FlowSet ID и Length;
    • Другие поля в зависимости от типа передаваемых данных.

Глядим FlowSet ID содержащий образец, начинается с полей FlowSet ID, потом Length, дальше:

  • Template ID (UInt16 2 байта) — неповторимый ID для всякого образца по которому передаются данные. Число от 256 до 65535;
  • Field Count (UInt16 2 байта) — число полей в образце. Дальше идут поочередно тип поля (Field Type) и размер (Field Length);
  • Field Type (UInt16 2 байта) — число определяющее тип поля. Все типы есть в спецификации протокола;
  • Field Length — длинна поля в байтах.

Глядим FlowSet ID содержащий данные, начинается с полей FlowSet ID, потом Length, дальше:

  • Данных… данных которые соответствуют полям и их размерам;
  • Padding — нули заполняющие до границы в 4 байта.

Есть еще так называемый опциональный образец и данные по нему. Я их рассматривать не буду, они мне не встречались, по этой причине в реализации библиотеки отсутствуют, но все дозволено дописать.

Составил UML диаграмму классов (с поддержкой NClass):
image
либо в pdf
И написал библиотеку для разбора приходящих пакетов.
Стержневой класс с которого все начинается, это Packet. Его исключительный конструктор принимает входящий пакет NetFlow в байтах и объект класса Templates, представляющий из себя список нынешнихTemplate (образцов).

Дальше в конструкторе класса Packet вызывается функция Parse, которая принимает объект классаTemplates.
В этой функции идет разбивка пакета на заголовок — 20 байт и последующая работа с ним через классHeader; на FlowSet`ы и передача всякого FlowSet`а на обработка соответствующему классу FlowSet.

Ввиду того, что FlowSet`ов может быть несколько, доводится вторую часть пакета (без 20 байт заголовка), исследовать и разбивать на различные FlowSet`ы. Знаменательно что в MikroTik`е FlowSet`ы в исключительном экземпляре в пакете, а вот пользуясь Netflow Simulator in C# удалось поработать с пакетами с несколькими FlowSet`ами в пакете. Помимо того вследствие ему был обнаружен комичный баг в реализации NetFlow v9 на MikroTik`е, о чем подробнее здесь.

Netflow Simulator in C#:
image

Вот участок кода разбивающий часть пакета на FlowSet`ы:

this._flowset = new List<FlowSet>();
Int32 length = _bytes.Length - 20;
Byte[] flowset = new Byte[length];
Array.Copy(_bytes, 20, flowset, 0, length);
byte[] reverse = flowset.Reverse().ToArray();
int templengh = 0;
while ((templengh   2) < flowset.Length)
{
	UInt16 lengths = BitConverter.ToUInt16(reverse, flowset.Length - sizeof(Int16) - (templengh 2));
	Byte[] bflowsets = new Byte[lengths];
	Array.Copy(flowset, templengh, bflowsets, 0, lengths);
	FlowSet flowsets = new FlowSet(bflowsets, templates);
	this._flowset.Add(flowsets);
	templengh  = lengths;
}

В классе Header идет разбор заголовка пакета на его поля. Раньше чем это сделать, выполняется реверсия заголовка:

this._bytes.Reverse().ToArray();

Дальше конвертируем биты в тот тип поля, которым он является, скажем поле version:

this._version = BitConverter.ToUInt16(reverse, this._bytes.Length - sizeof(Int16) - 0);

Да в Header поля sysUpTime имеет тип TimeSpan, приводим к этому типу:

get
{
	return new TimeSpan((long)this._uptime * 10000);
}

и поле UNIX Secs имеет тип DateTime:

get
{
	return new DateTime(1970, 1, 1).AddSeconds(this._secs);
}

Перейдем к обработке FlowSet`ов. Позже приобретения полей FlowSet ID и Length идет разбор остальных полей в зависимости от FlowSet ID. Если он равен 0 либо 1 то это образец, а если это число от 256 до 65535 то это данные.

Если это образец то передаем его обработку классу Template позже чего проверяем наше хранилище образцов (объект класса Templates) на присутствие образца с таким же ID и заменяем его, напротив легко добавляем образец.

Если это данные то проверяем есть ли в хранилище (объект класса Templates) такой образец (FlowSet ID ==Template ID) и если есть то копируем данный образец функцией DeepClone и заполняем его поля — Field, напротив ничего не делаем, чай без образца это легко комплект байтов.

функция DeepClone:

public static object DeepClone(object obj)
{
    object objResult = null;
    using (MemoryStream ms = new MemoryStream())
    {
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(ms, obj);

        ms.Position = 0;
        objResult = bf.Deserialize(ms);
    }
    return objResult;
}

Field — это поле, оно имеет следующие параметры:

  • Type — тип;
  • Length — размер;
  • Value — значение.

Причем Field в Template в хранилище находятся без параметров Value т.е. Value пусты, а вот при обработке пакетов Template в FlowSet в объекте Packet теснее содержит поля Value.

Помимо каждого этого есть еще перечисление FieldType — перечисление в котором имени типа соответствует номер данного типа. (параметр Type в Field)

Для работы данной библиотеки был написан пример:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetFlow;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace Consoles
{
    class Program
    {
        static void Main(string[] args)
        {
            Templates _templates = new Templates();

            Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            IPEndPoint iep = new IPEndPoint(IPAddress.Any, 9995);
            sock.Bind(iep);
            EndPoint ep = (EndPoint)iep;

            byte[] data = new byte[2048];

            while (true)
            {
                int recv = sock.ReceiveFrom(data, ref ep);
                Console.ReadKey();
                Console.Clear();
                byte[] bytes = new byte[recv];

                for (int i = 0; i < recv; i  )
                    bytes[i] = data[i];

                Packet packet = new Packet(bytes, _templates);

                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine(packet.ToString());
            }
            sock.Close();

            Console.ReadKey();
        }
    }
}

Создаем сокет и слушаем по UDP 9995 порт на нашем ПК. _templates — это наше хранилище образцов. Всякий приходящий пакет мы скармливаем объекту packet класса Packet передавая еще и наше хранилище образцов. А дальше исполняем packet.ToString() Это перегруженная функция выводит нам оглавление пакета и необходима только для проверки, что у нас все получается.

На этом с библиотекой все, сейчас ее дозволено применять для последующего написания Анализатора трафика по NetFlow протоколу.

Пример с MikroTik:

Получили пакет без наличия образца в хранилище:
image

Получили образец от сенсора:
image

Получили данные, для которых есть образец в хранилище:
image

Оплошность реализации NetFlow v9 в MikroTik


В процессе разбора данной темы бал обнаружен оплошность в реализации NetFlow v9 в MikroTik`е. Суть ошибки:
Поле Count в заголовке пакета (Packet Header) несет в себе:

Count
The total number of records in the Export Packet, which is the
sum of Options FlowSet records, Template FlowSet records, and
Data FlowSet records.


т.е. содержит все записи, во всех FlowSet`ах, а в MikroTik`е данное поле неизменно равно 1 (см. скрины выше), даже если передается несколько образцов либо данных. т.е. по логике MikroTik`а поле Count = числуFlowSet`ов (о чем они мне и написали в письме и видно по скринам), а должно быть равно всеобщему числу всех образцов и данных, как звучит в спецификации. По этой причине применять в разборе пакетов полеCount чревато.

Вот же пример от Netflow Simulator in C# (Хотелось бы получить данные и от Cisco, но у меня нет такой вероятности, может кто из читателей проверит это):

Получили пакет без наличия образца в хранилище (обратите внимание на Count):
image

Получили образец от сенсора (здесь единовременно два FlowSet`а пришло, что в MikroTik`е не бывает. Обратите внимание на Count он равен 7 = 1 образец и 6 записей с данными. По логике MikroTik`а Countдолжен был бы равен 2 = 2 FlowSet`а):
image

Получили данные, для которых есть образец в хранилище (обратите внимание на Count):
image

Ну и еще раз пакет в Wireshark Помечено поле Count:
image

Еще раз: буду дюже признателен каждому кто пришлет скрин с Wireshark`ом от Cisco. Вставлю его сюда.

Начальный код доступен тут.

При создании руководствовался:
Материал из Википедии: Netflow
Caligare: WHAT IS NETFLOW?
Спецификация протокола версии 9

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB