CでのNetFlow v.9パッケージの解析#

NetFlowは、ネットワークトラフィックを考慮してシスコシステムズが作成したネットワークプロトコルです。 このプロトコルの最も一般的なバージョンは5と9です。9 番目のバージョンは、送信されるデータに応じてテンプレートが使用されるため、より柔軟です。 5番目のバージョンでは、仕様に従ってデータが送信されます。
画像

NetFlowプロトコルトラフィック情報収集システムは、次のコンポーネントで構成されています。


C#のアナライザー機能の一部の開発、具体的にはNetFlowパッケージの分析について説明します

MikroTikルーターがセンサーとして使用されました。

ether1インターフェイスのNetFlowオンにします。
/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を介して:
画像

これで、 UDPポート9995192.168.0.100の IPアドレスを持つコンピューターでは、バージョン9のNetFlowパケットがUDP (またはSCTP )に到着します。 パッケージには、動作するものがあります。

着信パケットを解析する



プロトコル仕様を検討し結果、各NetFlowパケット(Nバイト)が以下で構成されていることがわかります。
  1. パケットヘッダー (20バイト)-フィールドを含む単一のコピーのパケットヘッダー:
    • バージョン番号UInt16-2バイト) -NetFlowバージョン番号。常に9です。
    • カウントUInt16-2バイト)-レコードの総数。 さらに、この分野の記事は冒険でした。
    • sysUpTime (UInt32-4バイト)-デバイスの開始からのミリ秒単位の時間-UpTime。
    • UNIX秒UInt32-4バイト)-パケットが送信された0000 UTC 1970からの秒数。
    • シーケンス番号UInt32-4バイト)-送信されたパケットのカウンター。パケットごとに常に増加しているため、それらの間のパケットが失われたかどうかを確認できます。
    • ソースIDUInt32-4バイト)-データストリーム番号。実際には、センサー側から複数のデータストリームを送信できます。

  2. FlowSet (N-20バイト)-テンプレート、データ... FlowSetは複数または1つにすることができます。 各FlowSetには、送信されるデータのタイプ(テンプレート、データ)から変更されていない2つのフィールドがあります。
    • FlowSet IDUInt16 2バイト)-テンプレートの場合は常に0、オプションのテンプレートの場合は1、データの場合はテンプレートIDと等しいため、255を超える(256〜65535)。
    • 長さUInt16 2バイト) -FlowSet全体のサイズとFlowSet IDおよびLengthフィールド。
    • 転送されるデータのタイプに応じたその他のフィールド。



テンプレートを含むFlowSet IDを見て、 FlowSet IDフィールドで始まり、次にLength 、次に:


データを含むFlowSet IDを見て、 FlowSet IDフィールドで始まり、次にLength 、次に:


いわゆるオプションのテンプレートとデータもあります。 私はそれらを考慮しません、彼らは私に会っていません、この理由で実装にライブラリがありませんが、すべてを追加することができます。

UMLクラス図をコンパイルしました( NClassを使用):
画像
またはpdfで
そして、彼は入ってくるパケットを解析するライブラリを書きました。
すべてが開始するメインクラスはPacketです。 その唯一のコンストラクタは、バイト単位の受信NetFlowパッケージと、現在のテンプレートのリストであるTemplatesクラスのオブジェクトを受け入れます。

次に、 Parse関数がPacketsクラスのコンストラクターで呼び出され、 Templatesクラスのオブジェクトを受け取ります。
この関数は、パケットをヘッダー(20バイト)に分割し、 Headerクラスを介してさらに処理します。 対応するFlowSetクラスへの処理のためのFlowSetの各FlowSetの転送。

いくつかのFlowSetが存在する可能性があるため、パケットの2番目の部分(ヘッダーの20バイトなし)を分析し、異なるFlowsetに分割する必要があります。 MikroTikパッケージ内の単一コピーにあるFlowSetが、 C#Netflow Simulatorを使用すると、パッケージ内に複数のFlowSetがあるパッケージで作業できることが注目に値します。 さらに、彼のおかげで、 MikroTikNetFlow v9の実装で面白いバグが見つかりました。詳細については、 こちらご覧ください

C#のNetflow Simulator
画像

FlowSet`sのパッケージの一部を壊すコードスニペットを次に示します。
 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(); 


次に、ビットをフィールドのタイプ(たとえば、バージョンフィールド)に変換します。
 this._version = BitConverter.ToUInt16(reverse, this._bytes.Length - sizeof(Int16) - 0); 


はい、 ヘッダーフィールド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クラスに渡し、同じIDを持つテンプレートの存在をテンプレートストア( Templatesクラスのオブジェクト)で確認して置き換えます。そうでない場合は、テンプレートを追加します。

このデータの場合、ストレージ( 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; } 


フィールドはフィールドであり、次のパラメーターがあります。


また、リポジトリ内のテンプレートの フィールドには、 パラメータがありません。 値は空ですが、 FlowSetテンプレートパッケージを処理する場合、 Packetオブジェクトには既にValueフィールドが含まれています。

これに加えて、 FieldType列挙もあります-型名がこの型の番号に対応する列挙です。 ( フィールドの パラメーター)

このライブラリが機能するための例が作成されました。
 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(); } } } 


ソケットを作成し、PCのUDP 9995ポートでリッスンします。 _templatesはテンプレートリポジトリです。 到着した各パケットをPacketクラスのパケットオブジェクトに送り、テンプレートストレージも渡します。 次に、 packet.ToString()を実行しますこのオーバーロードされた関数は、パケットの内容を表示し、すべてが正常に機能することを確認するためにのみ必要です。

ライブラリはこれですべてです。NetFlowプロトコルを使用してTraffic Analyzerをさらに記述するために使用できるようになりました。

MikroTikの例:

リポジトリにテンプレートのないパッケージを取得しました:
画像

センサーからテンプレートを取得しました:
画像

リポジトリにテンプレートがあるデータを取得しました:
画像

MikroTikの NetFlow v9の実装エラー


このトピックを分析する過程で、 MikroTikNetFlow v9の実装でエラーが見つかりました。 エラーの本質:
パケットヘッダー( パケットヘッダー )のカウントフィールドには以下が含まれます。
カウント
エクスポートパケット内のレコードの総数。
オプションFlowSetレコード、テンプレートFlowSetレコード、および
データFlowSetレコード。

つまり すべてのFlowSetのすべてのレコードとMikroTikのすべてのレコードが含まれます。このフィールドは、複数のテンプレートまたはデータが転送される場合でも、常に1に等しくなります(上記のスクリーンショットを参照)。 つまり MikroTikのロジックによると、 CountフィールドはFlowSetsの数(レターで私に書いたもので、スクリーンショットから見ることができます)であり、仕様にあるように、すべてのテンプレートとデータの総数に等しくなければなりません。 このため、パケット解析でCountフィールドを使用するのは困難です。

C#のNetflow Simulatorの例を次に示しますCiscoからもデータを受信したいのですが、そのような機会はありません。読者の1人がこれをチェックするかもしれません)。

リポジトリにテンプレートのないパッケージを受け取りました( Countに注意してください):
画像

センサーからテンプレートを取得しました(同時に2つのFlowSetsがありますが、 MikroTikが発生しないことが判明しました。 カウントに注意してください。テンプレートは7 = 1、データレコードは6です。MikroTikのロジックによると、 Countは2 = 2 FlowSet `a):
画像

リポジトリにテンプレートがあるデータを取得しました( Countに注意してください):
画像

繰り返しますが、 Wiresharkのパケットフィールドカウントはマークされています:
画像

繰り返しますが、 Cisco Wiresharkのomで画面を送信するすべての人に非常に感謝します。 ここに入れます。

ソースコードはこちらから入手できます

作成がガイドされたとき:
ウィキペディアの資料:Netflow
Caligare:NETFLOWとは?
プロトコル仕様バージョン9

今日(19:05 07/30/2013)

MikroTikは答えました:

MikroTikサポート[Dzintars] support@mikrotik.com
こんにちは

問題を報告していただきありがとうございます(記事の著者が正しく指摘しました
netflowパケットヘッダーのカウント値が常に正しく設定されているとは限りません)。 の
この問題は、RouterOSの次のバージョンで修正される予定です。

よろしく、
ジンター


UPD: RouterOS 6.2では、このバグは修正されました。
今日(13:22 09/13/2013)

MikroTikの書き込み:

MikroTikサポート[Dzintars] support@mikrotik.com
こんにちは

NetFlow V9カウントフィールドの問題はバージョン6.2で修正されました

よろしく、
ジンター

Source: https://habr.com/ru/post/J187820/


All Articles