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で修正されました



よろしく、

ジンター



All Articles