 
      NetFlowプロトコルトラフィック情報収集システムは、次のコンポーネントで構成されています。
- センサー デバイスを通過するトラフィックの統計を収集するデバイス(ルーター、L3スイッチ)。
- コレクター 。 センサーからデータを収集し、ストレージに入れます。
- アナライザー 。 コレクターが収集したデータを分析し、レポートを生成します。
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ポート9995で192.168.0.100の IPアドレスを持つコンピューターでは、バージョン9のNetFlowパケットがUDP (またはSCTP )に到着します。 パッケージには、動作するものがあります。
着信パケットを解析する
プロトコル仕様を検討した結果、各NetFlowパケット(Nバイト)が以下で構成されていることがわかります。
-   パケットヘッダー (20バイト)-フィールドを含む単一のコピーのパケットヘッダー: 
      
 
 - バージョン番号 ( UInt16-2バイト) -NetFlowバージョン番号。常に9です。
- カウント ( UInt16-2バイト)-レコードの総数。 さらに、この分野の記事は冒険でした。
- sysUpTime (UInt32-4バイト)-デバイスの開始からのミリ秒単位の時間-UpTime。
- UNIX秒 ( UInt32-4バイト)-パケットが送信された0000 UTC 1970からの秒数。
- シーケンス番号 ( UInt32-4バイト)-送信されたパケットのカウンター。パケットごとに常に増加しているため、それらの間のパケットが失われたかどうかを確認できます。
- ソースID ( UInt32-4バイト)-データストリーム番号。実際には、センサー側から複数のデータストリームを送信できます。
 
 
 
-   FlowSet (N-20バイト)-テンプレート、データ... FlowSetは複数または1つにすることができます。 各FlowSetには、送信されるデータのタイプ(テンプレート、データ)から変更されていない2つのフィールドがあります。 
      
 
 - FlowSet ID ( UInt16 2バイト)-テンプレートの場合は常に0、オプションのテンプレートの場合は1、データの場合はテンプレートIDと等しいため、255を超える(256〜65535)。
- 長さ ( UInt16 2バイト) -FlowSet全体のサイズとFlowSet IDおよびLengthフィールド。
- 転送されるデータのタイプに応じたその他のフィールド。
 
 
 
テンプレートを含むFlowSet IDを見て、 FlowSet IDフィールドで始まり、次にLength 、次に:
- テンプレートID ( UInt16 2バイト)-データが送信される各テンプレートの一意のID。 256から65535の数;
- フィールド数 ( UInt16 2バイト)-テンプレート内のフィールドの数。 次に、フィールドタイプ( Field Type )とサイズ( Field Length )があります。
- フィールドタイプ ( UInt16 2バイト)- フィールドのタイプを指定する数値。 すべてのタイプはプロトコル仕様にあります;
- フィールドの長さ -バイト単位のフィールドの長さ。
データを含むFlowSet IDを見て、 FlowSet IDフィールドで始まり、次にLength 、次に:
- データ...フィールドとそのサイズに対応するデータ。
- パディング -4バイトの境界までゼロを埋めます。
いわゆるオプションのテンプレートとデータもあります。 私はそれらを考慮しません、彼らは私に会っていません、この理由で実装にライブラリがありませんが、すべてを追加することができます。
UMLクラス図をコンパイルしました( NClassを使用):
 
 
      またはpdfで
そして、彼は入ってくるパケットを解析するライブラリを書きました。
すべてが開始するメインクラスはPacketです。 その唯一のコンストラクタは、バイト単位の受信NetFlowパッケージと、現在のテンプレートのリストであるTemplatesクラスのオブジェクトを受け入れます。
次に、 Parse関数がPacketsクラスのコンストラクターで呼び出され、 Templatesクラスのオブジェクトを受け取ります。
この関数は、パケットをヘッダー(20バイト)に分割し、 Headerクラスを介してさらに処理します。 対応するFlowSetクラスへの処理のためのFlowSetの各FlowSetの転送。
いくつかのFlowSetが存在する可能性があるため、パケットの2番目の部分(ヘッダーの20バイトなし)を分析し、異なるFlowsetに分割する必要があります。 MikroTikのパッケージ内の単一コピーにあるFlowSetが、 C#でNetflow Simulatorを使用すると、パッケージ内に複数のFlowSetがあるパッケージで作業できることが注目に値します。 さらに、彼のおかげで、 MikroTikのNetFlow 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の実装エラー
このトピックを分析する過程で、 MikroTikのNetFlow 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で修正されました
よろしく、
ジンター